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.

234 line
10 KiB

  1. -module(rebar_pkg_alias_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() -> [same_alias, diff_alias, diff_alias_vsn, transitive_alias,
  7. transitive_hash_mismatch].
  8. %% {uuid, {pkg, uuid}} = uuid
  9. %% {uuid, {pkg, alias}} = uuid on disk
  10. %% another run should yield the same lock file without error
  11. init_per_suite(Config) ->
  12. mock_config(?MODULE, Config).
  13. end_per_suite(Config) ->
  14. unmock_config(Config).
  15. init_per_testcase(same_alias, Config0) ->
  16. Config = rebar_test_utils:init_rebar_state(Config0,"same_alias_"),
  17. AppDir = ?config(apps, Config),
  18. rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
  19. RebarConf = rebar_test_utils:create_config(AppDir, [{deps, [{fakelib, {pkg, fakelib}}]}]),
  20. [{rebarconfig, RebarConf} | Config];
  21. init_per_testcase(diff_alias, Config0) ->
  22. Config = rebar_test_utils:init_rebar_state(Config0,"diff_alias_"),
  23. AppDir = ?config(apps, Config),
  24. rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
  25. RebarConf = rebar_test_utils:create_config(AppDir, [{deps, [{fakelib, {pkg, goodpkg}}]}]),
  26. [{rebarconfig, RebarConf} | Config];
  27. init_per_testcase(diff_alias_vsn, Config0) ->
  28. Config = rebar_test_utils:init_rebar_state(Config0,"diff_alias_vsn_"),
  29. AppDir = ?config(apps, Config),
  30. rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
  31. RebarConf = rebar_test_utils:create_config(AppDir, [{deps, [{fakelib, "1.0.0", {pkg, goodpkg}}]}]),
  32. [{rebarconfig, RebarConf} | Config];
  33. init_per_testcase(transitive_alias, Config0) ->
  34. Config = rebar_test_utils:init_rebar_state(Config0,"transitive_alias_vsn_"),
  35. AppDir = ?config(apps, Config),
  36. rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
  37. RebarConf = rebar_test_utils:create_config(AppDir, [{deps, [{topdep, "1.0.0", {pkg, topdep}}]}]),
  38. [{rebarconfig, RebarConf} | Config];
  39. init_per_testcase(transitive_hash_mismatch, Config0) ->
  40. Config = rebar_test_utils:init_rebar_state(Config0,"transitive_alias_vsn_"),
  41. AppDir = ?config(apps, Config),
  42. rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]),
  43. RebarConf = rebar_test_utils:create_config(AppDir, [{deps, [{topdep, "1.0.0", {pkg, topdep}}]}]),
  44. [{rebarconfig, RebarConf} | Config].
  45. end_per_testcase(_, Config) ->
  46. Config.
  47. same_alias(Config) ->
  48. {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
  49. rebar_test_utils:run_and_check(
  50. Config, RebarConfig, ["lock"],
  51. {ok, [{lock, "fakelib"}, {dep, "fakelib"}]}
  52. ).
  53. diff_alias(Config) ->
  54. %% even though the dep is 'fakelib' aliased as 'goodpkg' all
  55. %% internal records use 'fakelib' as a value. Just make sure
  56. %% the lock actually maintains the proper source as 'goodpkg'
  57. AppDir = ?config(apps, Config),
  58. Lockfile = filename:join([AppDir, "rebar.lock"]),
  59. {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
  60. rebar_test_utils:run_and_check(
  61. Config, RebarConfig, ["lock"],
  62. {ok, [{lock, "fakelib"},{dep, "fakelib"}]}
  63. ),
  64. {ok, [{_Vsn, LockData}|_]} = file:consult(Lockfile),
  65. ?assert(lists:any(fun({<<"fakelib">>,{pkg,<<"goodpkg">>,_},_}) -> true
  66. ; (_) -> false end, LockData)),
  67. %% An second run yields the same
  68. rebar_test_utils:run_and_check(
  69. Config, RebarConfig, ["lock"],
  70. {ok, [{lock, "fakelib"},{dep, "fakelib"}]}
  71. ),
  72. {ok, [{_Vsn, LockData}|_]} = file:consult(Lockfile),
  73. %% So does an upgrade
  74. rebar_test_utils:run_and_check(
  75. Config, RebarConfig, ["upgrade"],
  76. {ok, [{lock, "fakelib"},{dep, "fakelib"}]}
  77. ),
  78. {ok, [{_Vsn, LockData}|_]} = file:consult(Lockfile).
  79. diff_alias_vsn(Config) -> diff_alias(Config).
  80. transitive_alias(Config) ->
  81. %% ensure that the apps fetched under transitive aliases are
  82. %% locked properly, but also that they are stored in the right
  83. %% directory in the build dir to avoid breaking includes and
  84. %% static analysis tools that rely on the location to work
  85. AppDir = ?config(apps, Config),
  86. Lockfile = filename:join([AppDir, "rebar.lock"]),
  87. {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
  88. rebar_test_utils:run_and_check(
  89. Config, RebarConfig, ["lock"],
  90. {ok, [{lock, "topdep"},{dep, "topdep"},
  91. {lock,"transitive_app"},{dep,"transitive_app"}]}
  92. ),
  93. {ok, [{_Vsn, LockData}|_]} = file:consult(Lockfile),
  94. ?assert(lists:any(fun({<<"transitive_app">>,{pkg,<<"transitive">>,_},_}) -> true
  95. ; (_) -> false end, LockData)),
  96. AppDir = ?config(apps, Config),
  97. AliasedName = filename:join([AppDir, "_build", "default", "lib", "transitive_app"]),
  98. PkgName = filename:join([AppDir, "_build", "default", "lib", "transitive"]),
  99. ?assert(filelib:is_dir(AliasedName)),
  100. ?assertNot(filelib:is_dir(PkgName)),
  101. %% An second run yields the same
  102. rebar_test_utils:run_and_check(
  103. Config, RebarConfig, ["lock"],
  104. {ok, [{lock, "topdep"},{dep, "topdep"},
  105. {lock,"transitive_app"},{dep,"transitive_app"}]}
  106. ),
  107. {ok, [{_Vsn, LockData}|_]} = file:consult(Lockfile),
  108. ?assert(filelib:is_dir(AliasedName)),
  109. ?assertNot(filelib:is_dir(PkgName)),
  110. %% So does an upgrade
  111. rebar_test_utils:run_and_check(
  112. Config, RebarConfig, ["upgrade"],
  113. {ok, [{lock, "topdep"},{dep, "topdep"},
  114. {lock,"transitive_app"},{dep,"transitive_app"}]}
  115. ),
  116. {ok, [{_Vsn, LockData}|_]} = file:consult(Lockfile),
  117. ?assert(filelib:is_dir(AliasedName)),
  118. ?assertNot(filelib:is_dir(PkgName)),
  119. ok.
  120. transitive_hash_mismatch(Config) ->
  121. %% ensure that the apps fetched under transitive aliases are
  122. %% locked properly, but also that they are stored in the right
  123. %% directory in the build dir to avoid breaking includes and
  124. %% static analysis tools that rely on the location to work
  125. AppDir = ?config(apps, Config),
  126. Lockfile = filename:join([AppDir, "rebar.lock"]),
  127. {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
  128. rebar_test_utils:run_and_check(
  129. Config, RebarConfig, ["lock"],
  130. {ok, [{lock, "topdep"},{dep, "topdep"},
  131. {lock,"transitive_app"},{dep,"transitive_app"}]}
  132. ),
  133. {ok, [LockData|Attrs]} = file:consult(Lockfile),
  134. %% Change Lock hash data to cause a failure next time, but on transitive
  135. %% deps only
  136. NewLock = [LockData|lists:map(
  137. fun([{pkg_hash, Hashes}|Rest]) ->
  138. [{pkg_hash, [{<<"transitive_app">>, <<"fakehash">>}
  139. | lists:keydelete(<<"transitive_app">>, 1, Hashes)]}
  140. | Rest]
  141. ; (Attr) ->
  142. Attr
  143. end, Attrs)],
  144. {ok, Io} = file:open(Lockfile, [write]),
  145. [io:format(Io, "~p.~n", [Attr]) || Attr <- NewLock],
  146. file:close(Io),
  147. ct:pal("lock: ~p", [file:consult(Lockfile)]),
  148. ec_file:remove(filename:join([AppDir, "_build"]), [recursive]),
  149. ?assertMatch(
  150. {error, {rebar_fetch, {unexpected_hash, _, _, _}}},
  151. rebar_test_utils:run_and_check(Config, RebarConfig, ["lock"], return)
  152. ),
  153. ok.
  154. mock_config(Name, Config) ->
  155. {ChkFake, Etag} = create_lib(Name, Config, "fakelib"),
  156. {ChkTop, _} = create_lib(Name, Config, "topdep"),
  157. {ChkTrans, _} = create_lib(Name, Config, "transitive_app", "transitive"),
  158. ct:pal("{~p, _}",[ChkTop]),
  159. ct:pal("{~p, _}",[ChkTrans]),
  160. Priv = ?config(priv_dir, Config),
  161. TmpDir = filename:join([Priv, "tmp", atom_to_list(Name)]),
  162. %% Add an alias for goodpkg -> fakelib by hand
  163. AppDir = filename:join([Priv, "fakelib"]),
  164. CacheRoot = filename:join([Priv, "cache", atom_to_list(Name)]),
  165. CacheDir = filename:join([CacheRoot, "hex", "com", "test", "packages"]),
  166. rebar_test_utils:create_app(AppDir, "fakelib", "1.0.0", [kernel, stdlib]),
  167. ct:pal("{~p, ~p}",[ChkFake, Etag]),
  168. {ChkFake, Etag} = rebar_test_utils:package_app(AppDir, CacheDir, "goodpkg-1.0.0"),
  169. Tid = ets:new(registry_table, [public]),
  170. ets:insert_new(Tid, [
  171. {<<"fakelib">>,[[<<"1.0.0">>]]},
  172. {<<"goodpkg">>,[[<<"1.0.0">>]]},
  173. {<<"topdep">>,[[<<"1.0.0">>]]},
  174. {<<"transitive">>, [[<<"1.0.0">>]]},
  175. {{<<"fakelib">>,<<"1.0.0">>}, [[], ChkFake, [<<"rebar3">>]]},
  176. {{<<"goodpkg">>,<<"1.0.0">>}, [[], ChkFake, [<<"rebar3">>]]},
  177. {{<<"topdep">>,<<"1.0.0">>},
  178. [[
  179. [<<"transitive">>, <<"1.0.0">>, false, <<"transitive_app">>]
  180. ], ChkTop, [<<"rebar3">>]]},
  181. {{<<"transitive">>,<<"1.0.0">>}, [[], ChkTrans, [<<"rebar3">>]]}
  182. ]),
  183. ok = ets:tab2file(Tid, filename:join([CacheDir, "registry"])),
  184. ets:delete(Tid),
  185. %% The state returns us a fake registry
  186. meck:new(rebar_dir, [passthrough, no_link]),
  187. meck:expect(rebar_dir, global_cache_dir, fun(_) -> CacheRoot end),
  188. meck:new(rebar_packages, [passthrough, no_link]),
  189. meck:expect(rebar_packages, registry_dir, fun(_) -> {ok, CacheDir} end),
  190. meck:expect(rebar_packages, package_dir, fun(_) -> {ok, CacheDir} end),
  191. rebar_prv_update:hex_to_index(rebar_state:new()),
  192. %% Cache fetches are mocked -- we assume the server and clients are
  193. %% correctly used.
  194. meck:new(httpc, [passthrough, unsticky, no_link]),
  195. meck:expect(httpc, request,
  196. fun(get, {_Url, _Opts}, _, _, _) ->
  197. {ok, {{<<"1.0.0">>, 304, <<"Not Modified">>}, [{"etag", Etag}], <<>>}}
  198. end),
  199. %% Move all packages to cache
  200. NewConf = [{cache_root, CacheRoot},
  201. {cache_dir, CacheDir},
  202. {tmp_dir, TmpDir},
  203. {mock_table, Tid} | Config],
  204. NewConf.
  205. unmock_config(Config) ->
  206. meck:unload(),
  207. Config.
  208. create_lib(Name, Config, PkgName) ->
  209. create_lib(Name, Config, PkgName, PkgName).
  210. create_lib(Name, Config, AppName, PkgName) ->
  211. Priv = ?config(priv_dir, Config),
  212. AppDir = filename:join([Priv, PkgName]),
  213. CacheRoot = filename:join([Priv, "cache", atom_to_list(Name)]),
  214. CacheDir = filename:join([CacheRoot, "hex", "com", "test", "packages"]),
  215. filelib:ensure_dir(filename:join([CacheDir, "registry"])),
  216. rebar_test_utils:create_app(AppDir, AppName, "1.0.0", [kernel, stdlib]),
  217. rebar_test_utils:package_app(AppDir, CacheDir, PkgName++"-1.0.0").