Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

376 рядки
12 KiB

  1. -module(rebar_upgrade_SUITE).
  2. -include_lib("common_test/include/ct.hrl").
  3. -include_lib("eunit/include/eunit.hrl").
  4. -compile(export_all).
  5. all() -> [{group, git}].%, {group, pkg}].
  6. groups() ->
  7. [{all, [], [top_a, top_b, top_c, top_d1, top_d2, top_e,
  8. pair_a, pair_b, pair_c,
  9. triplet_a, triplet_b, triplet_c,
  10. tree_a, tree_b, tree_c]},
  11. {git, [], [{group, all}]},
  12. {pkg, [], [{group, all}]}].
  13. init_per_suite(Config) ->
  14. application:start(meck),
  15. Config.
  16. end_per_suite(_Config) ->
  17. application:stop(meck).
  18. init_per_group(git, Config) ->
  19. [{deps_type, git} | Config];
  20. init_per_group(pkg, Config) ->
  21. [{deps_type, pkg} | Config];
  22. init_per_group(_, Config) ->
  23. Config.
  24. end_per_group(_, Config) ->
  25. Config.
  26. init_per_testcase(Case, Config) ->
  27. DepsType = ?config(deps_type, Config),
  28. {Deps, UpDeps, ToUp, Expectations} = upgrades(Case),
  29. Expanded = expand_deps(DepsType, Deps),
  30. UpExpanded = expand_deps(DepsType, UpDeps),
  31. [{expected, normalize_unlocks(Expectations)},
  32. {mock, fun() -> mock_deps(DepsType, Expanded, []) end},
  33. {mock_update, fun() -> mock_deps(DepsType, UpExpanded, ToUp) end}
  34. | setup_project(Case, Config, Expanded, UpExpanded)].
  35. end_per_testcase(_, Config) ->
  36. meck:unload(),
  37. Config.
  38. setup_project(Case, Config0, Deps, UpDeps) ->
  39. DepsType = ?config(deps_type, Config0),
  40. Config = rebar_test_utils:init_rebar_state(
  41. Config0,
  42. atom_to_list(Case)++"_"++atom_to_list(DepsType)++"_"
  43. ),
  44. AppDir = ?config(apps, Config),
  45. rebar_test_utils:create_app(AppDir, "Root", "0.0.0", [kernel, stdlib]),
  46. TopDeps = top_level_deps(Deps),
  47. RebarConf = rebar_test_utils:create_config(AppDir, [{deps, TopDeps}]),
  48. [{rebarconfig, RebarConf},
  49. {next_top_deps, top_level_deps(UpDeps)} | Config].
  50. upgrades(top_a) ->
  51. %% Original tree
  52. {[{"A", "1", [{"B", [{"D", "1", []}]},
  53. {"C", [{"D", "2", []}]}]}
  54. ],
  55. %% Updated tree
  56. [{"A", "1", [{"B", [{"D", "3", []}]},
  57. {"C", [{"D", "2", []}]}]}
  58. ],
  59. %% Modified apps, gobally
  60. ["A","B","D"],
  61. %% upgrade vs. new tree
  62. {"A", [{"A","1"}, "B", "C", {"D","3"}]}};
  63. upgrades(top_b) ->
  64. %% Original tree
  65. {[{"A", "1", [{"B", [{"D", "1", []}]},
  66. {"C", [{"D", "2", []}]}]}
  67. ],
  68. %% Updated tree
  69. [{"A", "1", [{"B", [{"D", "3", []}]},
  70. {"C", [{"D", "2", []}]}]}
  71. ],
  72. %% Modified apps, gobally
  73. ["A","B","D"],
  74. %% upgrade vs. new tree
  75. {"B", {error, transitive_dependency}}};
  76. upgrades(top_c) ->
  77. %% Original tree
  78. {[{"A", "1", [{"B", [{"D", "1", []}]},
  79. {"C", [{"D", "2", []}]}]}
  80. ],
  81. %% Updated tree
  82. [{"A", "1", [{"B", [{"D", "3", []}]},
  83. {"C", [{"D", "2", []}]}]}
  84. ],
  85. %% Modified apps, gobally
  86. ["A","B","D"],
  87. %% upgrade vs. new tree
  88. {"C", {error, transitive_dependency}}};
  89. upgrades(top_d1) ->
  90. %% Original tree
  91. {[{"A", "1", [{"B", [{"D", "1", []}]},
  92. {"C", [{"D", "2", []}]}]}
  93. ],
  94. %% Updated tree
  95. [{"A", "1", [{"B", [{"D", "3", []}]},
  96. {"C", [{"D", "2", []}]}]}
  97. ],
  98. %% Modified apps, gobally
  99. ["A","B","D"],
  100. %% upgrade vs. new tree
  101. {"D", {error, transitive_dependency}}};
  102. upgrades(top_d2) ->
  103. %% Original tree
  104. {[{"A", "1", [{"B", [{"D", "1", []}]},
  105. {"C", [{"D", "2", []}]}]}
  106. ],
  107. %% Updated tree
  108. [{"A", "1", [{"B", [{"D", "3", []}]},
  109. {"C", [{"D", "2", []}]}]}
  110. ],
  111. %% Modified apps, gobally
  112. ["A","B","D"],
  113. %% upgrade vs. new tree
  114. {"D", {error, transitive_dependency}}};
  115. upgrades(top_e) ->
  116. %% Original tree
  117. {[{"A", "1", [{"B", [{"D", "1", []}]},
  118. {"C", [{"D", "2", []}]}]}
  119. ],
  120. %% Updated tree
  121. [{"A", "1", [{"B", [{"D", "3", []}]},
  122. {"C", [{"D", "2", []}]}]}
  123. ],
  124. %% Modified apps, gobally
  125. ["A","B","D"],
  126. %% upgrade vs. new tree
  127. {"E", {error, unknown_dependency}}};
  128. upgrades(pair_a) ->
  129. {[{"A", "1", [{"C", "1", []}]},
  130. {"B", "1", [{"D", "1", []}]}
  131. ],
  132. [{"A", "2", [{"C", "2", []}]},
  133. {"B", "2", [{"D", "2", []}]}
  134. ],
  135. ["A","B","C","D"],
  136. {"A", [{"A","2"},{"C","2"},{"B","1"},{"D","1"}]}};
  137. upgrades(pair_b) ->
  138. {[{"A", "1", [{"C", "1", []}]},
  139. {"B", "1", [{"D", "1", []}]}
  140. ],
  141. [{"A", "2", [{"C", "2", []}]},
  142. {"B", "2", [{"D", "2", []}]}
  143. ],
  144. ["A","B","C","D"],
  145. {"B", [{"A","1"},{"C","1"},{"B","2"},{"D","2"}]}};
  146. upgrades(pair_c) ->
  147. {[{"A", "1", [{"C", "1", []}]},
  148. {"B", "1", [{"D", "1", []}]}
  149. ],
  150. [{"A", "2", [{"C", "2", []}]},
  151. {"B", "2", [{"D", "2", []}]}
  152. ],
  153. ["A","B","C","D"],
  154. {"C", {error, transitive_dependency}}};
  155. upgrades(triplet_a) ->
  156. {[{"A", "1", [{"D",[]},
  157. {"E","3",[]}]},
  158. {"B", "1", [{"F","1",[]},
  159. {"G",[]}]},
  160. {"C", "0", [{"H","3",[]},
  161. {"I",[]}]}],
  162. [{"A", "1", [{"D",[]},
  163. {"E","2",[]}]},
  164. {"B", "1", [{"F","1",[]},
  165. {"G",[]}]},
  166. {"C", "1", [{"H","4",[]},
  167. {"I",[]}]}],
  168. ["A","C","E","H"],
  169. {"A", [{"A","1"}, "D", {"E","2"},
  170. {"B","1"}, {"F","1"}, "G",
  171. {"C","0"}, {"H","3"}, "I"]}};
  172. upgrades(triplet_b) ->
  173. {[{"A", "1", [{"D",[]},
  174. {"E","3",[]}]},
  175. {"B", "1", [{"F","1",[]},
  176. {"G",[]}]},
  177. {"C", "0", [{"H","3",[]},
  178. {"I",[]}]}],
  179. [{"A", "1", [{"D",[]},
  180. {"E","2",[]}]},
  181. {"B", "1", [{"F","1",[]},
  182. {"G",[]}]},
  183. {"C", "1", [{"H","4",[]},
  184. {"I",[]}]}],
  185. ["A","C","E","H"],
  186. {"B", [{"A","1"}, "D", {"E","3"},
  187. {"B","1"}, {"F","1"}, "G",
  188. {"C","0"}, {"H","3"}, "I"]}};
  189. upgrades(triplet_c) ->
  190. {[{"A", "1", [{"D",[]},
  191. {"E","3",[]}]},
  192. {"B", "1", [{"F","1",[]},
  193. {"G",[]}]},
  194. {"C", "0", [{"H","3",[]},
  195. {"I",[]}]}],
  196. [{"A", "1", [{"D",[]},
  197. {"E","2",[]}]},
  198. {"B", "1", [{"F","1",[]},
  199. {"G",[]}]},
  200. {"C", "1", [{"H","4",[]},
  201. {"I",[]}]}],
  202. ["A","C","E","H"],
  203. {"C", [{"A","1"}, "D", {"E","3"},
  204. {"B","1"}, {"F","1"}, "G",
  205. {"C","1"}, {"H","4"}, "I"]}};
  206. upgrades(tree_a) ->
  207. {[{"A", "1", [{"D",[{"J",[]}]},
  208. {"E",[{"I","1",[]}]}]},
  209. {"B", "1", [{"F",[]},
  210. {"G",[]}]},
  211. {"C", "1", [{"H",[]},
  212. {"I","2",[]}]}
  213. ],
  214. [{"A", "1", [{"D",[{"J",[]}]},
  215. {"E",[{"I","1",[]}]}]},
  216. {"B", "1", [{"F",[]},
  217. {"G",[]}]},
  218. {"C", "1", [{"H",[]}]}
  219. ],
  220. ["C"],
  221. {"A", [{"A","1"}, "D", "J", "E",
  222. {"B","1"}, "F", "G",
  223. {"C","1"}, "H", {"I","2"}]}};
  224. upgrades(tree_b) ->
  225. {[{"A", "1", [{"D",[{"J",[]}]},
  226. {"E",[{"I","1",[]}]}]},
  227. {"B", "1", [{"F",[]},
  228. {"G",[]}]},
  229. {"C", "1", [{"H",[]},
  230. {"I","2",[]}]}
  231. ],
  232. [{"A", "1", [{"D",[{"J",[]}]},
  233. {"E",[{"I","1",[]}]}]},
  234. {"B", "1", [{"F",[]},
  235. {"G",[]}]},
  236. {"C", "1", [{"H",[]}]}
  237. ],
  238. ["C"],
  239. {"B", [{"A","1"}, "D", "J", "E",
  240. {"B","1"}, "F", "G",
  241. {"C","1"}, "H", {"I","2"}]}};
  242. upgrades(tree_c) ->
  243. {[{"A", "1", [{"D",[{"J",[]}]},
  244. {"E",[{"I","1",[]}]}]},
  245. {"B", "1", [{"F",[]},
  246. {"G",[]}]},
  247. {"C", "1", [{"H",[]},
  248. {"I","2",[]}]}
  249. ],
  250. [{"A", "1", [{"D",[{"J",[]}]},
  251. {"E",[{"I","1",[]}]}]},
  252. {"B", "1", [{"F",[]},
  253. {"G",[]}]},
  254. {"C", "1", [{"H",[]}]}
  255. ],
  256. ["C"],
  257. {"C", [{"A","1"}, "D", "J", "E", {"I","1"},
  258. {"B","1"}, "F", "G",
  259. {"C","1"}, "H"]}}.
  260. %% TODO: add a test that verifies that unlocking files and then
  261. %% running the upgrade code is enough to properly upgrade things.
  262. top_level_deps([]) -> [];
  263. top_level_deps([{{Name, Vsn, Ref}, _} | Deps]) ->
  264. [{list_to_atom(Name), Vsn, Ref} | top_level_deps(Deps)];
  265. top_level_deps([{{pkg, Name, Vsn, _URL}, _} | Deps]) ->
  266. [{list_to_atom(Name), Vsn} | top_level_deps(Deps)].
  267. mock_deps(git, Deps, Upgrades) ->
  268. catch mock_git_resource:unmock(),
  269. ct:pal("mocked: ~p", [flat_deps(Deps)]),
  270. mock_git_resource:mock([{deps, flat_deps(Deps)}, {upgrade, Upgrades}]);
  271. mock_deps(pkg, Deps, Upgrades) ->
  272. catch mock_pkg_resource:unmock(),
  273. mock_pkg_resource:mock([{pkgdeps, flat_pkgdeps(Deps)}, {upgrade, Upgrades}]).
  274. flat_deps([]) -> [];
  275. flat_deps([{{Name,_Vsn,Ref}, Deps} | Rest]) ->
  276. [{{Name,vsn_from_ref(Ref)}, top_level_deps(Deps)}]
  277. ++
  278. flat_deps(Deps)
  279. ++
  280. flat_deps(Rest).
  281. vsn_from_ref({git, _, {_, Vsn}}) -> Vsn;
  282. vsn_from_ref({git, _, Vsn}) -> Vsn.
  283. flat_pkgdeps([]) -> [];
  284. flat_pkgdeps([{{pkg, Name, Vsn, _Url}, Deps} | Rest]) ->
  285. [{{iolist_to_binary(Name),iolist_to_binary(Vsn)}, top_level_deps(Deps)}]
  286. ++
  287. flat_pkgdeps(Deps)
  288. ++
  289. flat_pkgdeps(Rest).
  290. expand_deps(_, []) -> [];
  291. expand_deps(git, [{Name, Deps} | Rest]) ->
  292. Dep = {Name, ".*", {git, "https://example.org/user/"++Name++".git", "master"}},
  293. [{Dep, expand_deps(git, Deps)} | expand_deps(git, Rest)];
  294. expand_deps(git, [{Name, Vsn, Deps} | Rest]) ->
  295. Dep = {Name, Vsn, {git, "https://example.org/user/"++Name++".git", {tag, Vsn}}},
  296. [{Dep, expand_deps(git, Deps)} | expand_deps(git, Rest)];
  297. expand_deps(pkg, [{Name, Deps} | Rest]) ->
  298. Dep = {pkg, Name, "0.0.0", "https://example.org/user/"++Name++".tar.gz"},
  299. [{Dep, expand_deps(pkg, Deps)} | expand_deps(pkg, Rest)];
  300. expand_deps(pkg, [{Name, Vsn, Deps} | Rest]) ->
  301. Dep = {pkg, Name, Vsn, "https://example.org/user/"++Name++".tar.gz"},
  302. [{Dep, expand_deps(pkg, Deps)} | expand_deps(pkg, Rest)].
  303. normalize_unlocks({App, Locks}) ->
  304. {iolist_to_binary(App),
  305. normalize_unlocks_expect(Locks)};
  306. normalize_unlocks({App, Vsn, Locks}) ->
  307. {iolist_to_binary(App), iolist_to_binary(Vsn),
  308. normalize_unlocks_expect(Locks)}.
  309. normalize_unlocks_expect({error, Reason}) ->
  310. {error, Reason};
  311. normalize_unlocks_expect([]) ->
  312. [];
  313. normalize_unlocks_expect([{App,Vsn} | Rest]) ->
  314. [{dep, App, Vsn}
  315. | normalize_unlocks_expect(Rest)];
  316. normalize_unlocks_expect([App | Rest]) ->
  317. [{dep, App} | normalize_unlocks_expect(Rest)].
  318. top_a(Config) -> run(Config).
  319. top_b(Config) -> run(Config).
  320. top_c(Config) -> run(Config).
  321. top_d1(Config) -> run(Config).
  322. top_d2(Config) -> run(Config).
  323. top_e(Config) -> run(Config).
  324. pair_a(Config) -> run(Config).
  325. pair_b(Config) -> run(Config).
  326. pair_c(Config) -> run(Config).
  327. triplet_a(Config) -> run(Config).
  328. triplet_b(Config) -> run(Config).
  329. triplet_c(Config) -> run(Config).
  330. tree_a(Config) -> run(Config).
  331. tree_b(Config) -> run(Config).
  332. tree_c(Config) -> run(Config).
  333. run(Config) ->
  334. apply(?config(mock, Config), []),
  335. {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)),
  336. %% Install dependencies before re-mocking for an upgrade
  337. rebar_test_utils:run_and_check(Config, RebarConfig, ["lock"], {ok, []}),
  338. {App, Unlocks} = ?config(expected, Config),
  339. ct:pal("Upgrades: ~p -> ~p", [App, Unlocks]),
  340. Expectation = case Unlocks of
  341. {error, Term} -> {error, Term};
  342. _ -> {ok, Unlocks}
  343. end,
  344. apply(?config(mock_update, Config), []),
  345. NewRebarConf = rebar_test_utils:create_config(?config(apps, Config),
  346. [{deps, ?config(next_top_deps, Config)}]),
  347. {ok, NewRebarConfig} = file:consult(NewRebarConf),
  348. rebar_test_utils:run_and_check(
  349. Config, NewRebarConfig, ["upgrade", App], Expectation
  350. ).