Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

304 wiersze
13 KiB

  1. %% Test suite for the rebar pkg index caching and decompression
  2. %% mechanisms.
  3. -module(rebar_pkg_SUITE).
  4. -compile(export_all).
  5. -include_lib("common_test/include/ct.hrl").
  6. -include_lib("eunit/include/eunit.hrl").
  7. -define(bad_etag, "abcdef").
  8. -define(good_etag, "22e1d7387c9085a462340088a2a8ba67").
  9. -define(bad_checksum, <<"D576B442A68C7B92BACDE1EFE9C6E54D8D6C74BDB71D8175B9D3C6EC8C7B62A7">>).
  10. -define(good_checksum, <<"1C6CE379D191FBAB41B7905075E0BF87CBBE23C77CECE775C5A0B786B2244C35">>).
  11. all() -> [good_uncached, good_cached, badindexchk, badpkg,
  12. badhash_nocache, badhash_cache,
  13. bad_to_good, good_disconnect, bad_disconnect, pkgs_provider,
  14. find_highest_matching].
  15. init_per_suite(Config) ->
  16. application:start(meck),
  17. Config.
  18. end_per_suite(_Config) ->
  19. application:stop(meck).
  20. init_per_testcase(pkgs_provider=Name, Config) ->
  21. %% Need to mock out a registry for this test now because it will try to update it automatically
  22. Priv = ?config(priv_dir, Config),
  23. Tid = ets:new(registry_table, [public]),
  24. ets:insert_new(Tid, []),
  25. CacheRoot = filename:join([Priv, "cache", atom_to_list(Name)]),
  26. CacheDir = filename:join([CacheRoot, "hex", "com", "test", "packages"]),
  27. filelib:ensure_dir(filename:join([CacheDir, "registry"])),
  28. ok = ets:tab2file(Tid, filename:join([CacheDir, "registry"])),
  29. meck:new(rebar_packages, [passthrough]),
  30. meck:expect(rebar_packages, registry_dir, fun(_) -> {ok, CacheDir} end),
  31. meck:expect(rebar_packages, package_dir, fun(_) -> {ok, CacheDir} end),
  32. rebar_prv_update:hex_to_index(rebar_state:new()),
  33. Config;
  34. init_per_testcase(good_uncached=Name, Config0) ->
  35. Config = [{good_cache, false},
  36. {pkg, {<<"goodpkg">>, <<"1.0.0">>}}
  37. | Config0],
  38. mock_config(Name, Config);
  39. init_per_testcase(good_cached=Name, Config0) ->
  40. Pkg = {<<"goodpkg">>, <<"1.0.0">>},
  41. Config1 = [{good_cache, true},
  42. {pkg, Pkg}
  43. | Config0],
  44. Config = mock_config(Name, Config1),
  45. copy_to_cache(Pkg, Config),
  46. Config;
  47. init_per_testcase(badindexchk=Name, Config0) ->
  48. Config = [{good_cache, false},
  49. {pkg, {<<"badindexchk">>, <<"1.0.0">>}}
  50. | Config0],
  51. mock_config(Name, Config);
  52. init_per_testcase(badpkg=Name, Config0) ->
  53. Config = [{good_cache, false},
  54. {pkg, {<<"badpkg">>, <<"1.0.0">>}}
  55. | Config0],
  56. mock_config(Name, Config);
  57. init_per_testcase(badhash_nocache=Name, Config0) ->
  58. Config = [{good_cache, false},
  59. {pkg, {<<"goodpkg">>, <<"1.0.0">>}}
  60. | Config0],
  61. mock_config(Name, Config);
  62. init_per_testcase(badhash_cache=Name, Config0) ->
  63. Pkg = {<<"goodpkg">>, <<"1.0.0">>},
  64. Config1 = [{good_cache, true},
  65. {pkg, Pkg}
  66. | Config0],
  67. Config = mock_config(Name, Config1),
  68. copy_to_cache(Pkg, Config),
  69. Config;
  70. init_per_testcase(bad_to_good=Name, Config0) ->
  71. Config1 = [{good_cache, false},
  72. {pkg, {<<"goodpkg">>, <<"1.0.0">>}}
  73. | Config0],
  74. Config = mock_config(Name, Config1),
  75. Source = filename:join(?config(data_dir, Config), <<"badpkg-1.0.0.tar">>),
  76. Dest = filename:join(?config(cache_dir, Config), <<"goodpkg-1.0.0.tar">>),
  77. ec_file:copy(Source, Dest),
  78. Config;
  79. init_per_testcase(good_disconnect=Name, Config0) ->
  80. Pkg = {<<"goodpkg">>, <<"1.0.0">>},
  81. Config1 = [{good_cache, true},
  82. {pkg, Pkg}
  83. | Config0],
  84. Config = mock_config(Name, Config1),
  85. copy_to_cache(Pkg, Config),
  86. meck:unload(httpc),
  87. meck:new(httpc, [passthrough, unsticky]),
  88. meck:expect(httpc, request, fun(_, _, _, _, _) -> {error, econnrefused} end),
  89. Config;
  90. init_per_testcase(bad_disconnect=Name, Config0) ->
  91. Pkg = {<<"goodpkg">>, <<"1.0.0">>},
  92. Config1 = [{good_cache, false},
  93. {pkg, Pkg}
  94. | Config0],
  95. Config = mock_config(Name, Config1),
  96. meck:unload(httpc),
  97. meck:new(httpc, [passthrough, unsticky]),
  98. meck:expect(httpc, request, fun(_, _, _, _, _) -> {error, econnrefused} end),
  99. Config;
  100. init_per_testcase(Name, Config0) ->
  101. Config = [{good_cache, false},
  102. {pkg, {<<"goodpkg">>, <<"1.0.0">>}}
  103. | Config0],
  104. mock_config(Name, Config).
  105. end_per_testcase(_, Config) ->
  106. unmock_config(Config),
  107. Config.
  108. good_uncached(Config) ->
  109. Tmp = ?config(tmp_dir, Config),
  110. {Pkg,Vsn} = ?config(pkg, Config),
  111. State = ?config(state, Config),
  112. ?assertEqual({ok, true},
  113. rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)),
  114. Cache = ?config(cache_dir, Config),
  115. ?assert(filelib:is_regular(filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".tar">>))).
  116. good_cached(Config) ->
  117. Tmp = ?config(tmp_dir, Config),
  118. {Pkg,Vsn} = ?config(pkg, Config),
  119. State = ?config(state, Config),
  120. Cache = ?config(cache_dir, Config),
  121. CachedFile = filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".tar">>),
  122. ?assert(filelib:is_regular(CachedFile)),
  123. {ok, Content} = file:read_file(CachedFile),
  124. ?assertEqual({ok, true},
  125. rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)),
  126. {ok, Content} = file:read_file(CachedFile).
  127. badindexchk(Config) ->
  128. Tmp = ?config(tmp_dir, Config),
  129. {Pkg,Vsn} = ?config(pkg, Config),
  130. State = ?config(state, Config),
  131. ?assertMatch({bad_registry_checksum, _Path},
  132. rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)),
  133. %% The cached file is there for forensic purposes
  134. Cache = ?config(cache_dir, Config),
  135. ?assert(filelib:is_regular(filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".tar">>))).
  136. badpkg(Config) ->
  137. Tmp = ?config(tmp_dir, Config),
  138. {Pkg,Vsn} = ?config(pkg, Config),
  139. State = ?config(state, Config),
  140. ?assertMatch({bad_download, _Path},
  141. rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)),
  142. %% The cached file is there for forensic purposes
  143. Cache = ?config(cache_dir, Config),
  144. ?assert(filelib:is_regular(filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".tar">>))).
  145. badhash_nocache(Config) ->
  146. Tmp = ?config(tmp_dir, Config),
  147. {Pkg,Vsn} = ?config(pkg, Config),
  148. State = ?config(state, Config),
  149. ?assertMatch({unexpected_hash, _Path, ?bad_checksum, ?good_checksum},
  150. rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?bad_checksum}, State)),
  151. %% The cached file is there for forensic purposes
  152. Cache = ?config(cache_dir, Config),
  153. ?assert(filelib:is_regular(filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".tar">>))).
  154. badhash_cache(Config) ->
  155. Tmp = ?config(tmp_dir, Config),
  156. {Pkg,Vsn} = ?config(pkg, Config),
  157. Cache = ?config(cache_dir, Config),
  158. State = ?config(state, Config),
  159. CachedFile = filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".tar">>),
  160. ?assert(filelib:is_regular(CachedFile)),
  161. {ok, Content} = file:read_file(CachedFile),
  162. ?assertMatch({unexpected_hash, _Path, ?bad_checksum, ?good_checksum},
  163. rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?bad_checksum}, State)),
  164. %% The cached file is there still, unchanged.
  165. ?assert(filelib:is_regular(CachedFile)),
  166. ?assertEqual({ok, Content}, file:read_file(CachedFile)).
  167. bad_to_good(Config) ->
  168. Tmp = ?config(tmp_dir, Config),
  169. {Pkg,Vsn} = ?config(pkg, Config),
  170. State = ?config(state, Config),
  171. Cache = ?config(cache_dir, Config),
  172. CachedFile = filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".tar">>),
  173. ?assert(filelib:is_regular(CachedFile)),
  174. {ok, Contents} = file:read_file(CachedFile),
  175. ?assertEqual({ok, true},
  176. rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)),
  177. %% Cache has refreshed
  178. ?assert({ok, Contents} =/= file:read_file(CachedFile)).
  179. good_disconnect(Config) ->
  180. Tmp = ?config(tmp_dir, Config),
  181. {Pkg,Vsn} = ?config(pkg, Config),
  182. State = ?config(state, Config),
  183. Cache = ?config(cache_dir, Config),
  184. CachedFile = filename:join(Cache, <<Pkg/binary, "-", Vsn/binary, ".tar">>),
  185. ?assert(filelib:is_regular(CachedFile)),
  186. {ok, Content} = file:read_file(CachedFile),
  187. ?assertEqual({ok, true},
  188. rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)),
  189. {ok, Content} = file:read_file(CachedFile).
  190. bad_disconnect(Config) ->
  191. Tmp = ?config(tmp_dir, Config),
  192. {Pkg,Vsn} = ?config(pkg, Config),
  193. State = ?config(state, Config),
  194. ?assertEqual({fetch_fail, Pkg, Vsn},
  195. rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)).
  196. pkgs_provider(Config) ->
  197. Config1 = rebar_test_utils:init_rebar_state(Config),
  198. rebar_test_utils:run_and_check(
  199. Config1, [], ["pkgs"],
  200. {ok, []}
  201. ).
  202. find_highest_matching(_Config) ->
  203. State = rebar_state:new(),
  204. {ok, Vsn} = rebar_packages:find_highest_matching(
  205. <<"test">>, <<"1.0.0">>, <<"goodpkg">>, <<"1.0.0">>, package_index, State),
  206. ?assertEqual(<<"1.0.1">>, Vsn),
  207. {ok, Vsn1} = rebar_packages:find_highest_matching(
  208. <<"test">>, <<"1.0.0">>, <<"goodpkg">>, <<"1.0">>, package_index, State),
  209. ?assertEqual(<<"1.1.1">>, Vsn1),
  210. {ok, Vsn2} = rebar_packages:find_highest_matching(
  211. <<"test">>, <<"1.0.0">>, <<"goodpkg">>, <<"2.0">>, package_index, State),
  212. ?assertEqual(<<"2.0.0">>, Vsn2),
  213. %% regression test. ~> constraints higher than the available packages would result
  214. %% in returning the first package version instead of 'none'.
  215. ?assertEqual(none, rebar_packages:find_highest_matching(<<"test">>, <<"1.0.0">>, <<"goodpkg">>,
  216. <<"~> 5.0">>, package_index, State)).
  217. %%%%%%%%%%%%%%%
  218. %%% Helpers %%%
  219. %%%%%%%%%%%%%%%
  220. mock_config(Name, Config) ->
  221. Priv = ?config(priv_dir, Config),
  222. CacheRoot = filename:join([Priv, "cache", atom_to_list(Name)]),
  223. TmpDir = filename:join([Priv, "tmp", atom_to_list(Name)]),
  224. Tid = ets:new(registry_table, [public]),
  225. ets:insert_new(Tid, [
  226. {<<"badindexchk">>,[[<<"1.0.0">>]]},
  227. {<<"goodpkg">>,[[<<"1.0.0">>, <<"1.0.1">>, <<"1.1.1">>, <<"2.0.0">>]]},
  228. {<<"badpkg">>,[[<<"1.0.0">>]]},
  229. {{<<"badindexchk">>,<<"1.0.0">>}, [[], ?bad_checksum, [<<"rebar3">>]]},
  230. {{<<"goodpkg">>,<<"1.0.0">>}, [[], ?good_checksum, [<<"rebar3">>]]},
  231. {{<<"goodpkg">>,<<"1.0.1">>}, [[], ?good_checksum, [<<"rebar3">>]]},
  232. {{<<"goodpkg">>,<<"1.1.1">>}, [[], ?good_checksum, [<<"rebar3">>]]},
  233. {{<<"goodpkg">>,<<"2.0.0">>}, [[], ?good_checksum, [<<"rebar3">>]]},
  234. {{<<"badpkg">>,<<"1.0.0">>}, [[], ?good_checksum, [<<"rebar3">>]]}
  235. ]),
  236. CacheDir = filename:join([CacheRoot, "hex", "com", "test", "packages"]),
  237. filelib:ensure_dir(filename:join([CacheDir, "registry"])),
  238. ok = ets:tab2file(Tid, filename:join([CacheDir, "registry"])),
  239. %% The state returns us a fake registry
  240. meck:new(rebar_state, [passthrough]),
  241. meck:expect(rebar_state, get,
  242. fun(_State, rebar_packages_cdn, _Default) ->
  243. "http://test.com/"
  244. end),
  245. meck:new(rebar_dir, [passthrough]),
  246. meck:expect(rebar_dir, global_cache_dir, fun(_) -> CacheRoot end),
  247. meck:new(rebar_packages, [passthrough]),
  248. meck:expect(rebar_packages, registry_dir, fun(_) -> {ok, CacheDir} end),
  249. meck:expect(rebar_packages, package_dir, fun(_) -> {ok, CacheDir} end),
  250. rebar_prv_update:hex_to_index(rebar_state:new()),
  251. meck:new(rebar_prv_update, [passthrough]),
  252. meck:expect(rebar_prv_update, do, fun(State) -> {ok, State} end),
  253. %% Cache fetches are mocked -- we assume the server and clients are
  254. %% correctly used.
  255. GoodCache = ?config(good_cache, Config),
  256. {Pkg,Vsn} = ?config(pkg, Config),
  257. PkgFile = <<Pkg/binary, "-", Vsn/binary, ".tar">>,
  258. {ok, PkgContents} = file:read_file(filename:join(?config(data_dir, Config), PkgFile)),
  259. meck:new(httpc, [passthrough, unsticky]),
  260. meck:expect(httpc, request,
  261. fun(get, {_Url, _Opts}, _, _, _) when GoodCache ->
  262. {ok, {{Vsn, 304, <<"Not Modified">>}, [{"etag", ?good_etag}], <<>>}};
  263. (get, {_Url, _Opts}, _, _, _) ->
  264. {ok, {{Vsn, 200, <<"OK">>}, [{"etag", ?good_etag}], PkgContents}}
  265. end),
  266. [{cache_root, CacheRoot},
  267. {cache_dir, CacheDir},
  268. {tmp_dir, TmpDir},
  269. {mock_table, Tid} | Config].
  270. unmock_config(Config) ->
  271. meck:unload(),
  272. catch ets:delete(?config(mock_table, Config)).
  273. copy_to_cache({Pkg,Vsn}, Config) ->
  274. Name = <<Pkg/binary, "-", Vsn/binary, ".tar">>,
  275. Source = filename:join(?config(data_dir, Config), Name),
  276. Dest = filename:join(?config(cache_dir, Config), Name),
  277. ec_file:copy(Source, Dest).