From 56b7d88975aa8da6446857cfd92de0825024bf63 Mon Sep 17 00:00:00 2001 From: Tristan Sloughter Date: Thu, 13 Sep 2018 19:36:00 -0600 Subject: support for hex v2, multiple repository fetching, private organizations (#1884) * update to hex_core for hex-v2 repo support (#1865) * update to hex_core for hex-v2 repo support This patch adds only single repo hex-v2 support through hex_core. Packages no longer filtered out by buildtool metadata and the package index is updated per-package instead of fetched as one large ets dump. * tell travis to also build hex_core branch * support list of repos for hex packages (#1866) * support list of repos for hex packages repos are defined under the hex key in rebar configs. They can be defined at the top level of a project or globally, but not in profiles and the repos configured in dependencies are also ignored. Searching for packages involves first checking for a match in the local repo index cache, in the order repos are defined. If not found each repo is checked through the hex api for any known versions of the package and the first repo with a version that fits the constraint is used. * add {repos, replace, []} for overriding the global & default repos * add hex auth handling for repos (#1874) auth token are kept in a hex.config file that is modified by the rebar3 hex plugin. Repo names that have a : separating a parent and child are considered organizations. The parent repo's auth will be included with the child. So an organization named hexpm:rebar3_test will include any hexpm auth tokens found in the rebar3_test organization's configuration. * move packages to top level of of hexpm cache dir (#1876) * move packages to top level of of hexpm cache dir * append organization name to parent's repo_url when parsing repos * only eval config scripts and apply overrides once per app (#1879) * only eval config scripts and apply overrides once per app * move new resource behaviour to rebar_resource_v2 and keep v1 * cleanup use of rebar_resource module and unused functions * cleanup error messages and unused code * when discovering apps support mix packages as unbuilt apps (#1882) * use hex_core tarball unpacking support in pkg resource (#1883) * use hex_core tarball unpacking support in pkg resource * ignore etag if package doesn't exist and delete if checksum fails * add back tests for bad package checksums * improve bad registry checksum error message --- test/mock_git_resource.erl | 17 +- test/mock_pkg_resource.erl | 100 ++++-- test/rebar_compile_SUITE.erl | 95 ++--- test/rebar_deps_SUITE.erl | 130 ++++--- test/rebar_install_deps_SUITE.erl | 108 +++--- test/rebar_localfs_resource.erl | 8 +- test/rebar_localfs_resource_v2.erl | 50 +++ test/rebar_pkg_SUITE.erl | 148 ++++---- test/rebar_pkg_SUITE_data/badindexchk-1.0.0.tar | Bin 10240 -> 10240 bytes test/rebar_pkg_SUITE_data/badpkg-1.0.0.tar | Bin 10240 -> 10240 bytes test/rebar_pkg_SUITE_data/goodpkg-1.0.0.tar | Bin 10240 -> 10240 bytes test/rebar_pkg_alias_SUITE.erl | 108 ++++-- test/rebar_pkg_repos_SUITE.erl | 331 ++++++++++++++++++ test/rebar_resource_SUITE.erl | 9 +- test/rebar_test_utils.erl | 48 +-- test/rebar_upgrade_SUITE.erl | 442 ++++++++++++------------ 16 files changed, 1029 insertions(+), 565 deletions(-) create mode 100644 test/rebar_localfs_resource_v2.erl create mode 100644 test/rebar_pkg_repos_SUITE.erl (limited to 'test') diff --git a/test/mock_git_resource.erl b/test/mock_git_resource.erl index e922af3..5673349 100644 --- a/test/mock_git_resource.erl +++ b/test/mock_git_resource.erl @@ -27,7 +27,7 @@ mock(Opts) -> mock(Opts, create_app). mock(Opts, CreateType) -> - meck:new(?MOD, [no_link]), + meck:new(?MOD, [no_link, passthrough]), mock_lock(Opts), mock_update(Opts), mock_vsn(Opts), @@ -46,8 +46,8 @@ unmock() -> mock_lock(_) -> meck:expect( ?MOD, lock, - fun(_AppDir, Git) -> - case Git of + fun(AppInfo, _) -> + case rebar_app_info:source(AppInfo) of {git, Url, {tag, Ref}} -> {git, Url, {ref, Ref}}; {git, Url, {ref, Ref}} -> {git, Url, {ref, Ref}}; {git, Url} -> {git, Url, {ref, "0.0.0"}}; @@ -62,7 +62,8 @@ mock_update(Opts) -> % ct:pal("TOUp: ~p", [ToUpdate]), meck:expect( ?MOD, needs_update, - fun(_Dir, {git, Url, _Ref}) -> + fun(AppInfo, _) -> + {git, Url, _Ref} = rebar_app_info:source(AppInfo), App = app(Url), % ct:pal("Needed update? ~p (~p) -> ~p", [App, {Url,_Ref}, lists:member(App, ToUpdate)]), lists:member(App, ToUpdate) @@ -78,7 +79,8 @@ mock_vsn(Opts) -> Default = proplists:get_value(default_vsn, Opts, "0.0.0"), meck:expect( ?MOD, make_vsn, - fun(Dir) -> + fun(AppInfo, _) -> + Dir = rebar_app_info:dir(AppInfo), case filelib:wildcard("*.app.src", filename:join([Dir,"src"])) of [AppSrc] -> {ok, App} = file:consult(AppSrc), @@ -108,7 +110,8 @@ mock_download(Opts, CreateType) -> Overrides = proplists:get_value(override_vsn, Opts, []), meck:expect( ?MOD, download, - fun (Dir, Git, _) -> + fun (Dir, AppInfo, _, _) -> + Git = rebar_app_info:source(AppInfo), filelib:ensure_dir(Dir), {git, Url, {_, Vsn}} = normalize_git(Git, Overrides, Default), App = app(Url), @@ -118,7 +121,7 @@ mock_download(Opts, CreateType) -> [kernel, stdlib] ++ [element(1,D) || D <- AppDeps] ), rebar_test_utils:create_config(Dir, [{deps, AppDeps}]++Config), - {ok, 'WHATEVER'} + ok end). %%%%%%%%%%%%%%% diff --git a/test/mock_pkg_resource.erl b/test/mock_pkg_resource.erl index 5769988..9a31461 100644 --- a/test/mock_pkg_resource.erl +++ b/test/mock_pkg_resource.erl @@ -3,6 +3,8 @@ -export([mock/0, mock/1, unmock/0]). -define(MOD, rebar_pkg_resource). +-include("rebar.hrl"). + %%%%%%%%%%%%%%%%% %%% Interface %%% %%%%%%%%%%%%%%%%% @@ -26,7 +28,7 @@ mock() -> mock([]). Vsn :: string(), Hash :: string() | undefined. mock(Opts) -> - meck:new(?MOD, [no_link]), + meck:new(?MOD, [no_link, passthrough]), mock_lock(Opts), mock_update(Opts), mock_vsn(Opts), @@ -44,7 +46,10 @@ unmock() -> %% @doc creates values for a lock file. mock_lock(_) -> - meck:expect(?MOD, lock, fun(_AppDir, Source) -> Source end). + meck:expect(?MOD, lock, fun(AppInfo, _) -> + {pkg, Name, Vsn, Hash, _RepoConfig} = rebar_app_info:source(AppInfo), + {pkg, Name, Vsn, Hash} + end). %% @doc The config passed to the `mock/2' function can specify which apps %% should be updated on a per-name basis: `{update, ["App1", "App3"]}'. @@ -52,7 +57,8 @@ mock_update(Opts) -> ToUpdate = proplists:get_value(upgrade, Opts, []), meck:expect( ?MOD, needs_update, - fun(_Dir, {pkg, App, _Vsn, _Hash}) -> + fun(AppInfo, _) -> + {pkg, App, _Vsn, _Hash, _} = rebar_app_info:source(AppInfo), lists:member(binary_to_list(App), ToUpdate) end). @@ -60,7 +66,7 @@ mock_update(Opts) -> mock_vsn(_Opts) -> meck:expect( ?MOD, make_vsn, - fun(_Dir) -> + fun(_AppInfo, _) -> {error, "Replacing version of type pkg not supported."} end). @@ -77,30 +83,32 @@ mock_download(Opts) -> Config = proplists:get_value(config, Opts, []), meck:expect( ?MOD, download, - fun (Dir, {pkg, AppBin, Vsn, _}, _) -> - App = binary_to_list(AppBin), + fun (Dir, AppInfo, _, _) -> + {pkg, AppBin, Vsn, _, _} = rebar_app_info:source(AppInfo), + App = rebar_utils:to_list(AppBin), filelib:ensure_dir(Dir), AppDeps = proplists:get_value({App,Vsn}, Deps, []), - {ok, AppInfo} = rebar_test_utils:create_app( - Dir, App, binary_to_list(Vsn), + {ok, AppInfo1} = rebar_test_utils:create_app( + Dir, App, rebar_utils:to_list(Vsn), [kernel, stdlib] ++ [element(1,D) || D <- AppDeps] ), rebar_test_utils:create_config(Dir, [{deps, AppDeps}]++Config), - TarApp = App++"-"++binary_to_list(Vsn)++".tar", - Tarball = filename:join([Dir, TarApp]), - Contents = filename:join([Dir, "contents.tar.gz"]), - Files = all_files(rebar_app_info:dir(AppInfo)), - ok = erl_tar:create(Contents, - archive_names(Dir, App, Vsn, Files), - [compressed]), - ok = erl_tar:create(Tarball, - [{"contents.tar.gz", Contents}], - []), + + TarApp = App++"-"++rebar_utils:to_list(Vsn)++".tar", + + Metadata = #{<<"app">> => AppBin, + <<"version">> => Vsn}, + + Files = all_files(rebar_app_info:dir(AppInfo1)), + {ok, {Tarball, _Checksum}} = hex_tarball:create(Metadata, archive_names(Dir, Files)), + Archive = filename:join([Dir, TarApp]), + file:write_file(Archive, Tarball), + Cache = proplists:get_value(cache_dir, Opts, filename:join(Dir,"cache")), Cached = filename:join([Cache, TarApp]), filelib:ensure_dir(Cached), - rebar_file_utils:mv(Tarball, Cached), - {ok, true} + rebar_file_utils:mv(Archive, Cached), + ok end). %% @doc On top of the pkg resource mocking, we need to mock the package @@ -110,16 +118,18 @@ mock_download(Opts) -> %% specific applications otherwise listed. mock_pkg_index(Opts) -> Deps = proplists:get_value(pkgdeps, Opts, []), + Repos = proplists:get_value(repos, Opts, [<<"hexpm">>]), Skip = proplists:get_value(not_in_index, Opts, []), %% Dict: {App, Vsn}: [{<<"link">>, <<>>}, {<<"deps">>, []}] %% Index: all apps and deps in the index Dict = find_parts(Deps, Skip), + to_index(Deps, Dict, Repos), meck:new(rebar_packages, [passthrough, no_link]), - meck:expect(rebar_packages, packages, - fun(_State) -> to_index(Deps, Dict) end), + meck:expect(rebar_packages, update_package, + fun(_, _, _State) -> ok end), meck:expect(rebar_packages, verify_table, - fun(_State) -> to_index(Deps, Dict), true end). + fun(_State) -> true end). %%%%%%%%%%%%%%% %%% Helpers %%% @@ -128,7 +138,7 @@ mock_pkg_index(Opts) -> all_files(Dir) -> filelib:wildcard(filename:join([Dir, "**"])). -archive_names(Dir, _App, _Vsn, Files) -> +archive_names(Dir, Files) -> [{(F -- Dir) -- "/", F} || F <- Files]. find_parts(Apps, Skip) -> find_parts(Apps, Skip, dict:new()). @@ -143,24 +153,42 @@ find_parts([{AppName, Deps}|Rest], Skip, Acc) -> Acc), find_parts(Rest, Skip, AccNew) end. +parse_deps(Deps) -> + [{maps:get(app, D, Name), {pkg, Name, Constraint, undefined}} || D=#{package := Name, + requirement := Constraint} <- Deps]. + +to_index(AllDeps, Dict, Repos) -> + catch ets:delete(?PACKAGE_TABLE), + rebar_packages:new_package_table(), -to_index(AllDeps, Dict) -> - catch ets:delete(package_index), - ets:new(package_index, [named_table, public]), dict:fold( - fun(K, Deps, _) -> - DepsList = [{DKB, {pkg, DKB, DVB, undefined}} + fun({N, V}, Deps, _) -> + DepsList = [#{package => DKB, + app => DKB, + requirement => DVB, + source => {pkg, DKB, DVB, undefined}} || {DK, DV} <- Deps, DKB <- [ec_cnv:to_binary(DK)], DVB <- [ec_cnv:to_binary(DV)]], - ets:insert(package_index, {K, DepsList, <<"checksum">>}) + Repo = rebar_test_utils:random_element(Repos), + ets:insert(?PACKAGE_TABLE, #package{key={N, V, Repo}, + dependencies=parse_deps(DepsList), + retired=false, + checksum = <<"checksum">>}) end, ok, Dict), - ets:insert(package_index, {package_index_version, 3}), + lists:foreach(fun({{Name, Vsn}, _}) -> - case ets:lookup(package_index, ec_cnv:to_binary(Name)) of - [{_, Vsns}] -> - ets:insert(package_index, {ec_cnv:to_binary(Name), [ec_cnv:to_binary(Vsn) | Vsns]}); - _ -> - ets:insert(package_index, {ec_cnv:to_binary(Name), [ec_cnv:to_binary(Vsn)]}) + case lists:any(fun(R) -> + ets:member(?PACKAGE_TABLE, {ec_cnv:to_binary(Name), Vsn, R}) + end, Repos) of + false -> + Repo = rebar_test_utils:random_element(Repos), + ets:insert(?PACKAGE_TABLE, #package{key={ec_cnv:to_binary(Name), Vsn, Repo}, + dependencies=[], + retired=false, + checksum = <<"checksum">>}); + true -> + ok end end, AllDeps). + diff --git a/test/rebar_compile_SUITE.erl b/test/rebar_compile_SUITE.erl index 6470b06..10effda 100644 --- a/test/rebar_compile_SUITE.erl +++ b/test/rebar_compile_SUITE.erl @@ -1,69 +1,6 @@ -module(rebar_compile_SUITE). --export([suite/0, - init_per_suite/1, - end_per_suite/1, - init_per_testcase/2, - end_per_testcase/2, - init_per_group/2, - end_per_group/2, - all/0, - groups/0, - build_basic_app/1, paths_basic_app/1, clean_basic_app/1, - build_release_apps/1, paths_release_apps/1, clean_release_apps/1, - build_checkout_apps/1, paths_checkout_apps/1, - build_checkout_deps/1, paths_checkout_deps/1, - build_basic_srcdirs/1, paths_basic_srcdirs/1, - build_release_srcdirs/1, paths_release_srcdirs/1, - build_unbalanced_srcdirs/1, paths_unbalanced_srcdirs/1, - build_basic_extra_dirs/1, paths_basic_extra_dirs/1, clean_basic_extra_dirs/1, - build_release_extra_dirs/1, paths_release_extra_dirs/1, clean_release_extra_dirs/1, - build_unbalanced_extra_dirs/1, paths_unbalanced_extra_dirs/1, - build_extra_dirs_in_project_root/1, - paths_extra_dirs_in_project_root/1, - clean_extra_dirs_in_project_root/1, - recompile_when_hrl_changes/1, - recompile_when_included_hrl_changes/1, - recompile_when_opts_included_hrl_changes/1, - recompile_when_opts_change/1, - dont_recompile_when_opts_dont_change/1, - dont_recompile_yrl_or_xrl/1, - deps_in_path/1, - delete_beam_if_source_deleted/1, - checkout_priority/1, - highest_version_of_pkg_dep/1, - parse_transform_test/1, - erl_first_files_test/1, - mib_test/1, - umbrella_mib_first_test/1, - only_default_transitive_deps/1, - clean_all/1, - override_deps/1, - override_add_deps/1, - override_del_deps/1, - override_opts/1, - override_add_opts/1, - override_del_opts/1, - profile_deps/1, - profile_override_deps/1, - profile_override_add_deps/1, - profile_override_del_deps/1, - profile_override_opts/1, - profile_override_add_opts/1, - profile_override_del_opts/1, - deps_build_in_prod/1, - include_file_relative_to_working_directory/1, - include_file_in_src/1, - include_file_relative_to_working_directory_test/1, - include_file_in_src_test/1, - include_file_in_src_test_multiapp/1, - dont_recompile_when_erl_compiler_options_env_does_not_change/1, - recompile_when_erl_compiler_options_env_changes/1, - always_recompile_when_erl_compiler_options_set/1, - recompile_when_parse_transform_inline_changes/1, - recompile_when_parse_transform_as_opt_changes/1, - recursive/1,no_recursive/1, - regex_filter_skip/1, regex_filter_regression/1]). +-compile(export_all). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). @@ -89,6 +26,7 @@ all() -> profile_deps, deps_build_in_prod, override_deps, override_add_deps, override_del_deps, override_opts, override_add_opts, override_del_opts, + apply_overrides_exactly_once, profile_override_deps, profile_override_add_deps, profile_override_del_deps, profile_override_opts, profile_override_add_opts, profile_override_del_opts, include_file_relative_to_working_directory, include_file_in_src, @@ -1405,6 +1343,35 @@ override_opts(Config) -> true = lists:member(compressed, proplists:get_value(options, Mod:module_info(compile), [])), false = lists:member(warn_missing_spec, proplists:get_value(options, Mod:module_info(compile), [])). +%% test for fix of https://github.com/erlang/rebar3/issues/1801 +%% only apply overrides once +%% verify by having an override add the macro TEST to the dep some_dep +%% building under `ct` will fail if the `add` is applied more than once +apply_overrides_exactly_once(Config) -> + AppDir = ?config(apps, Config), + + Deps = rebar_test_utils:expand_deps(git, [{"some_dep", "0.0.1", [{"other_dep", "0.0.1", []}]}]), + TopDeps = rebar_test_utils:top_level_deps(Deps), + + {SrcDeps, _} = rebar_test_utils:flat_deps(Deps), + mock_git_resource:mock([{deps, SrcDeps}]), + + Name = rebar_test_utils:create_random_name("app1_"), + Vsn = rebar_test_utils:create_random_vsn(), + rebar_test_utils:create_app(AppDir, Name, Vsn, [kernel, stdlib]), + + RebarConfig = [{deps, TopDeps}, + {overrides, [ + {add, some_dep, [ + {erl_opts, [{d, 'TEST'}]} + ]} + ]}], + + rebar_test_utils:create_config(AppDir, RebarConfig), + + rebar_test_utils:run_and_check( + Config, RebarConfig, ["ct", "--compile_only"], {ok, [{app, Name}, {dep, "some_dep"}], "test"}). + override_add_opts(Config) -> AppDir = ?config(apps, Config), diff --git a/test/rebar_deps_SUITE.erl b/test/rebar_deps_SUITE.erl index ae50ea3..8a3362d 100644 --- a/test/rebar_deps_SUITE.erl +++ b/test/rebar_deps_SUITE.erl @@ -188,27 +188,27 @@ deps(flat) -> [], {ok, ["B", "C"]}}; deps(pick_highest_left) -> - {[{"B", [{"C", "2", []}]}, - {"C", "1", []}], - [{"C","2"}], - {ok, ["B", {"C", "1"}]}}; + {[{"B", [{"C", "2.0.0", []}]}, + {"C", "1.0.0", []}], + [{"C","2.0.0"}], + {ok, ["B", {"C", "1.0.0"}]}}; deps(pick_highest_right) -> - {[{"B", "1", []}, - {"C", [{"B", "2", []}]}], - [{"B","2"}], - {ok, [{"B","1"}, "C"]}}; + {[{"B", "1.0.0", []}, + {"C", [{"B", "2.0.0", []}]}], + [{"B","2.0.0"}], + {ok, [{"B","1.0.0"}, "C"]}}; deps(pick_smallest1) -> - {[{"B", [{"D", "1", []}]}, - {"C", [{"D", "2", []}]}], - [{"D","2"}], + {[{"B", [{"D", "1.0.0", []}]}, + {"C", [{"D", "2.0.0", []}]}], + [{"D","2.0.0"}], %% we pick D1 because B < C - {ok, ["B","C",{"D","1"}]}}; + {ok, ["B","C",{"D","1.0.0"}]}}; deps(pick_smallest2) -> - {[{"C", [{"D", "2", []}]}, - {"B", [{"D", "1", []}]}], - [{"D","2"}], + {[{"C", [{"D", "2.0.0", []}]}, + {"B", [{"D", "1.0.0", []}]}], + [{"D","2.0.0"}], %% we pick D1 because B < C - {ok, ["B","C",{"D","1"}]}}; + {ok, ["B","C",{"D","1.0.0"}]}}; deps(circular1) -> {[{"B", [{"A", []}]}, % A is the top-level app {"C", []}], @@ -222,15 +222,17 @@ deps(circular2) -> deps(circular_skip) -> %% Never spot the circular dep due to being to low in the deps tree %% in source deps - {[{"B", [{"C", "2", [{"B", []}]}]}, - {"C", "1", [{"D",[]}]}], - [{"C","2"}], - {ok, ["B", {"C","1"}, "D"]}}. + {[{"B", [{"C", "2.0.0", [{"B", []}]}]}, + {"C", "1.0.0", [{"D",[]}]}], + [{"C","2.0.0"}], + {ok, ["B", {"C","1.0.0"}, "D"]}}. setup_project(Case, Config0, Deps) -> DepsType = ?config(deps_type, Config0), + %% spread packages across 3 repos randomly + Repos = [<<"test-repo-1">>, <<"test-repo-2">>, <<"hexpm">>], Config = rebar_test_utils:init_rebar_state( - Config0, + [{repos, Repos} | Config0], atom_to_list(Case)++"_"++atom_to_list(DepsType)++"_" ), AppDir = ?config(apps, Config), @@ -239,7 +241,7 @@ setup_project(Case, Config0, Deps) -> RebarConf = rebar_test_utils:create_config(AppDir, [{deps, TopDeps}]), {SrcDeps, PkgDeps} = rebar_test_utils:flat_deps(Deps), mock_git_resource:mock([{deps, SrcDeps}]), - mock_pkg_resource:mock([{pkgdeps, PkgDeps}]), + mock_pkg_resource:mock([{pkgdeps, PkgDeps}, {repos, Repos}]), [{rebarconfig, RebarConf} | Config]. mock_warnings() -> @@ -412,70 +414,62 @@ https_os_proxy_settings(_Config) -> httpc:get_option(https_proxy, rebar)). semver_matching_lt(_Config) -> - Dep = <<"test">>, - Dep1 = {Dep, <<"1.0.0">>, Dep, Dep}, MaxVsn = <<"0.2.0">>, Vsns = [<<"0.1.7">>, <<"0.1.9">>, <<"0.1.8">>, <<"0.2.0">>, <<"0.2.1">>], - ?assertEqual([{Dep, {pkg, Dep, <<"0.1.9">>, undefined}}], - rebar_prv_update:cmpl_(undefined, MaxVsn, Vsns, [], Dep1, + ?assertEqual({ok, <<"0.1.9">>}, + rebar_packages:cmpl_(undefined, MaxVsn, Vsns, fun ec_semver:lt/2)). semver_matching_lte(_Config) -> - Dep = <<"test">>, - Dep1 = {Dep, <<"1.0.0">>, Dep, Dep}, MaxVsn = <<"0.2.0">>, Vsns = [<<"0.1.7">>, <<"0.1.9">>, <<"0.1.8">>, <<"0.2.0">>, <<"0.2.1">>], - ?assertEqual([{Dep, {pkg, Dep, <<"0.2.0">>, undefined}}], - rebar_prv_update:cmpl_(undefined, MaxVsn, Vsns, [], Dep1, + ?assertEqual({ok, <<"0.2.0">>}, + rebar_packages:cmpl_(undefined, MaxVsn, Vsns, fun ec_semver:lte/2)). semver_matching_gt(_Config) -> - Dep = <<"test">>, - Dep1 = {Dep, <<"1.0.0">>, Dep, Dep}, MaxVsn = <<"0.2.0">>, Vsns = [<<"0.1.7">>, <<"0.1.9">>, <<"0.1.8">>, <<"0.2.0">>, <<"0.2.1">>], - ?assertEqual([{Dep, {pkg, Dep, <<"0.2.1">>, undefined}}], - rebar_prv_update:cmp_(undefined, MaxVsn, Vsns, [], Dep1, + ?assertEqual({ok, <<"0.2.1">>}, + rebar_packages:cmp_(undefined, MaxVsn, Vsns, fun ec_semver:gt/2)). semver_matching_gte(_Config) -> - Dep = <<"test">>, - Dep1 = {Dep, <<"1.0.0">>, Dep, Dep}, MaxVsn = <<"0.2.0">>, Vsns = [<<"0.1.7">>, <<"0.1.9">>, <<"0.1.8">>, <<"0.2.0">>], - ?assertEqual([{Dep, {pkg, Dep, <<"0.2.0">>, undefined}}], - rebar_prv_update:cmp_(undefined, MaxVsn, Vsns, [], Dep1, + ?assertEqual({ok, <<"0.2.0">>}, + rebar_packages:cmp_(undefined, MaxVsn, Vsns, fun ec_semver:gt/2)). valid_version(_Config) -> - ?assert(rebar_prv_update:valid_vsn(<<"0.1">>)), - ?assert(rebar_prv_update:valid_vsn(<<"0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<" 0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<" 0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<"<0.1">>)), - ?assert(rebar_prv_update:valid_vsn(<<"<0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<"< 0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<"< 0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<">0.1">>)), - ?assert(rebar_prv_update:valid_vsn(<<">0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<"> 0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<"> 0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<"<=0.1">>)), - ?assert(rebar_prv_update:valid_vsn(<<"<=0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<"<= 0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<"<= 0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<">=0.1">>)), - ?assert(rebar_prv_update:valid_vsn(<<">=0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<">= 0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<">= 0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<"==0.1">>)), - ?assert(rebar_prv_update:valid_vsn(<<"==0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<"== 0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<"== 0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<"~>0.1">>)), - ?assert(rebar_prv_update:valid_vsn(<<"~>0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<"~> 0.1.0">>)), - ?assert(rebar_prv_update:valid_vsn(<<"~> 0.1.0">>)), - ?assertNot(rebar_prv_update:valid_vsn(<<"> 0.1.0 and < 0.2.0">>)), + ?assert(rebar_packages:valid_vsn(<<"0.1">>)), + ?assert(rebar_packages:valid_vsn(<<"0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<" 0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<" 0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<"<0.1">>)), + ?assert(rebar_packages:valid_vsn(<<"<0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<"< 0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<"< 0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<">0.1">>)), + ?assert(rebar_packages:valid_vsn(<<">0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<"> 0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<"> 0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<"<=0.1">>)), + ?assert(rebar_packages:valid_vsn(<<"<=0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<"<= 0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<"<= 0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<">=0.1">>)), + ?assert(rebar_packages:valid_vsn(<<">=0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<">= 0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<">= 0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<"==0.1">>)), + ?assert(rebar_packages:valid_vsn(<<"==0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<"== 0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<"== 0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<"~>0.1">>)), + ?assert(rebar_packages:valid_vsn(<<"~>0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<"~> 0.1.0">>)), + ?assert(rebar_packages:valid_vsn(<<"~> 0.1.0">>)), + ?assertNot(rebar_packages:valid_vsn(<<"> 0.1.0 and < 0.2.0">>)), ok. @@ -504,5 +498,5 @@ in_warnings(git, Warns, NameRaw, VsnRaw) -> in_warnings(pkg, Warns, NameRaw, VsnRaw) -> Name = iolist_to_binary(NameRaw), Vsn = iolist_to_binary(VsnRaw), - 1 =< length([1 || {_, [AppName, {pkg, _, AppVsn, _}]} <- Warns, + 1 =< length([1 || {_, [AppName, {pkg, _, AppVsn}]} <- Warns, AppName =:= Name, AppVsn =:= Vsn]). diff --git a/test/rebar_install_deps_SUITE.erl b/test/rebar_install_deps_SUITE.erl index 3dbbf63..04cc441 100644 --- a/test/rebar_install_deps_SUITE.erl +++ b/test/rebar_install_deps_SUITE.erl @@ -121,27 +121,27 @@ deps(flat) -> [], {ok, ["B", "C"]}}; deps(pick_highest_left) -> - {[{"B", [{"C", "2", []}]}, - {"C", "1", []}], - [{"C","2"}], - {ok, ["B", {"C", "1"}]}}; + {[{"B", [{"C", "2.0.0", []}]}, + {"C", "1.0.0", []}], + [{"C","2.0.0"}], + {ok, ["B", {"C", "1.0.0"}]}}; deps(pick_highest_right) -> - {[{"B", "1", []}, - {"C", [{"B", "2", []}]}], - [{"B","2"}], - {ok, [{"B","1"}, "C"]}}; + {[{"B", "1.0.0", []}, + {"C", [{"B", "2.0.0", []}]}], + [{"B","2.0.0"}], + {ok, [{"B","1.0.0"}, "C"]}}; deps(pick_smallest1) -> - {[{"B", [{"D", "1", []}]}, - {"C", [{"D", "2", []}]}], - [{"D","2"}], + {[{"B", [{"D", "1.0.0", []}]}, + {"C", [{"D", "2.0.0", []}]}], + [{"D","2.0.0"}], %% we pick D1 because B < C - {ok, ["B","C",{"D","1"}]}}; + {ok, ["B","C",{"D","1.0.0"}]}}; deps(pick_smallest2) -> - {[{"C", [{"D", "2", []}]}, - {"B", [{"D", "1", []}]}], - [{"D","2"}], + {[{"C", [{"D", "2.0.0", []}]}, + {"B", [{"D", "1.0.0", []}]}], + [{"D","2.0.0"}], %% we pick D1 because B < C - {ok, ["B","C",{"D","1"}]}}; + {ok, ["B","C",{"D","1.0.0"}]}}; deps(circular1) -> {[{"B", [{"A", []}]}, % A is the top-level app {"C", []}], @@ -155,14 +155,14 @@ deps(circular2) -> deps(circular_skip) -> %% Never spot the circular dep due to being to low in the deps tree %% in source deps - {[{"B", [{"C", "2", [{"B", []}]}]}, - {"C", "1", [{"D",[]}]}], - [{"C","2"}], - {ok, ["B", {"C","1"}, "D"]}}; + {[{"B", [{"C", "2.0.0", [{"B", []}]}]}, + {"C", "1.0.0", [{"D",[]}]}], + [{"C","2.0.0"}], + {ok, ["B", {"C","1.0.0"}, "D"]}}; deps(fail_conflict) -> - {[{"B", [{"C", "2", []}]}, - {"C", "1", []}], - [{"C","2"}], + {[{"B", [{"C", "2.0.0", []}]}, + {"C", "1.0.0", []}], + [{"C","2.0.0"}], rebar_abort}; deps(default_profile) -> {[{"B", []}, @@ -216,39 +216,39 @@ mdeps(m_pick_source3) -> [], {ok, ["B"]}}; mdeps(m_pick_source4) -> - {[{"b", [{"d", "1", []}]}, - {"C", [{"D", "1", []}]}], - [{"D", "1"}], - {ok, ["b", "C", {"d", "1"}]}}; + {[{"b", [{"d", "1.0.0", []}]}, + {"C", [{"D", "1.0.0", []}]}], + [{"D", "1.0.0"}], + {ok, ["b", "C", {"d", "1.0.0"}]}}; mdeps(m_pick_source5) -> - {[{"B", [{"d", "1", []}]}, - {"C", [{"D", "1", []}]}], - [{"D", "1"}], - {ok, ["B", "C", {"d", "1"}]}}; + {[{"B", [{"d", "1.0.0", []}]}, + {"C", [{"D", "1.0.0", []}]}], + [{"D", "1.0.0"}], + {ok, ["B", "C", {"d", "1.0.0"}]}}; mdeps(m_source_to_pkg) -> {[{"B", [{"c",[{"d", []}]}]}], [], {ok, ["B", "c", "d"]}}; mdeps(m_pkg_level1) -> - {[{"B", [{"D", [{"e", "2", []}]}]}, - {"C", [{"e", "1", []}]}], - [{"e","2"}], - {ok, ["B","C","D",{"e","1"}]}}; + {[{"B", [{"D", [{"e", "2.0.0", []}]}]}, + {"C", [{"e", "1.0.0", []}]}], + [{"e","2.0.0"}], + {ok, ["B","C","D",{"e","1.0.0"}]}}; mdeps(m_pkg_level2) -> - {[{"B", [{"e", "1", []}]}, - {"C", [{"D", [{"e", "2", []}]}]}], - [{"e","2"}], - {ok, ["B","C","D",{"e","1"}]}}; + {[{"B", [{"e", "1.0.0", []}]}, + {"C", [{"D", [{"e", "2.0.0", []}]}]}], + [{"e","2.0.0"}], + {ok, ["B","C","D",{"e","1.0.0"}]}}; mdeps(m_pkg_level3_alpha_order) -> - {[{"B", [{"d", [{"f", "1", []}]}]}, - {"C", [{"E", [{"f", "2", []}]}]}], - [{"f","2"}], - {ok, ["B","C","d","E",{"f","1"}]}}; + {[{"B", [{"d", [{"f", "1.0.0", []}]}]}, + {"C", [{"E", [{"f", "2.0.0", []}]}]}], + [{"f","2.0.0"}], + {ok, ["B","C","d","E",{"f","1.0.0"}]}}; mdeps(m_pkg_level3) -> - {[{"B", [{"d", [{"f", "1", []}]}]}, - {"C", [{"E", [{"G", [{"f", "2", []}]}]}]}], - [{"f","2"}], - {ok, ["B","C","d","E","G",{"f","1"}]}}. + {[{"B", [{"d", [{"f", "1.0.0", []}]}]}, + {"C", [{"E", [{"G", [{"f", "2.0.0", []}]}]}]}], + [{"f","2.0.0"}], + {ok, ["B","C","d","E","G",{"f","1.0.0"}]}}. setup_project(fail_conflict, Config0, Deps) -> DepsType = ?config(deps_type, Config0), @@ -289,8 +289,8 @@ setup_project(nondefault_pick_highest, Config0, _) -> ), AppDir = ?config(apps, Config), rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]), - DefaultDeps = rebar_test_utils:expand_deps(DepsType, [{"B", [{"C", "1", []}]}]), - ProfileDeps = rebar_test_utils:expand_deps(DepsType, [{"C", "2", []}]), + DefaultDeps = rebar_test_utils:expand_deps(DepsType, [{"B", [{"C", "1.0.0", []}]}]), + ProfileDeps = rebar_test_utils:expand_deps(DepsType, [{"C", "2.0.0", []}]), DefaultTop = rebar_test_utils:top_level_deps(DefaultDeps), ProfileTop = rebar_test_utils:top_level_deps(ProfileDeps), RebarConf = rebar_test_utils:create_config( @@ -412,19 +412,19 @@ nondefault_pick_highest(Config) -> {ok, RebarConfig} = file:consult(?config(rebarconfig, Config)), rebar_test_utils:run_and_check( Config, RebarConfig, ["lock"], - {ok, [{dep, "B"}, {lock, "B"}, {lock, "C", "1"}, {dep, "C", "1"}], "default"} + {ok, [{dep, "B"}, {lock, "B"}, {lock, "C", "1.0.0"}, {dep, "C", "1.0.0"}], "default"} ), rebar_test_utils:run_and_check( Config, RebarConfig, ["as", "nondef", "lock"], - {ok, [{dep, "B"}, {lock, "B"}, {lock, "C", "1"}, {dep, "C", "2"}], "nondef"} + {ok, [{dep, "B"}, {lock, "B"}, {lock, "C", "1.0.0"}, {dep, "C", "2.0.0"}], "nondef"} ), rebar_test_utils:run_and_check( Config, RebarConfig, ["lock"], - {ok, [{dep, "B"}, {lock, "B"}, {dep, "C", "1"}, {lock, "C", "1"}], "default"} + {ok, [{dep, "B"}, {lock, "B"}, {dep, "C", "1.0.0"}, {lock, "C", "1.0.0"}], "default"} ), rebar_test_utils:run_and_check( Config, RebarConfig, ["as", "nondef", "lock"], - {ok, [{dep, "B"}, {lock, "B"}, {lock, "C", "1"}, {dep, "C", "2"}], "nondef"} + {ok, [{dep, "B"}, {lock, "B"}, {lock, "C", "1.0.0"}, {dep, "C", "2.0.0"}], "nondef"} ). m_flat1(Config) -> run(Config). @@ -475,5 +475,5 @@ in_warnings(git, Warns, NameRaw, VsnRaw) -> in_warnings(pkg, Warns, NameRaw, VsnRaw) -> Name = iolist_to_binary(NameRaw), Vsn = iolist_to_binary(VsnRaw), - 1 =< length([1 || {_, [AppName, {pkg, _, AppVsn, _}]} <- Warns, + 1 =< length([1 || {_, [AppName, {pkg, _, AppVsn}]} <- Warns, AppName =:= Name, AppVsn =:= Vsn]). diff --git a/test/rebar_localfs_resource.erl b/test/rebar_localfs_resource.erl index d60421e..3d1296a 100644 --- a/test/rebar_localfs_resource.erl +++ b/test/rebar_localfs_resource.erl @@ -2,6 +2,7 @@ %% ex: ts=4 sw=4 et %% %% @doc A localfs custom resource (for testing purposes only) +%% implementing the deprecated rebar_resource instead of v2 %% %% ``` %% {deps, [ @@ -13,13 +14,18 @@ -behaviour(rebar_resource). --export([lock/2 +-export([init/1 + ,lock/2 ,download/3 ,needs_update/2 ,make_vsn/1]). -include_lib("eunit/include/eunit.hrl"). +-spec init(rebar_state:t()) -> {ok, term()}. +init(_State) -> + {ok, #{}}. + lock(AppDir, {localfs, Path, _Ref}) -> lock(AppDir, {localfs, Path}); lock(_AppDir, {localfs, Path}) -> diff --git a/test/rebar_localfs_resource_v2.erl b/test/rebar_localfs_resource_v2.erl new file mode 100644 index 0000000..52af4d4 --- /dev/null +++ b/test/rebar_localfs_resource_v2.erl @@ -0,0 +1,50 @@ +%% -*- erlang-indent-level: 4;indent-tabs-mode: nil -*- +%% ex: ts=4 sw=4 et +%% +%% @doc A localfs custom resource (for testing purposes only) +%% +%% ``` +%% {deps, [ +%% %% Application files are copied from "/path/to/app_name" +%% {app_name, {localfs, "/path/to/app_name", undefined}} +%% ]}. +%% ''' +-module(rebar_localfs_resource_v2). + +-behaviour(rebar_resource_v2). + +-export([init/2 + ,lock/2 + ,download/4 + ,needs_update/2 + ,make_vsn/2]). + +-include_lib("eunit/include/eunit.hrl"). + +-spec init(atom(), rebar_state:t()) -> {ok, term()}. +init(Type, _State) -> + Resource = rebar_resource_v2:new(Type, ?MODULE, #{}), + {ok, Resource}. + +lock(AppInfo, _) -> + case rebar_app_info:source(AppInfo) of + {localfs, Path, _Ref} -> + {localfs, Path, undefined}; + {localfs, Path} -> + {localfs, Path, undefined} + end. + +needs_update(_AppInfo, _) -> + false. + +download(TmpDir, AppInfo, State, _) -> + download_(TmpDir, rebar_app_info:source(AppInfo), State). + +download_(TmpDir, {localfs, Path, _Ref}, State) -> + download_(TmpDir, {localfs, Path}, State); +download_(TmpDir, {localfs, Path}, _State) -> + ok = rebar_file_utils:cp_r(filelib:wildcard(Path ++ "/*"), TmpDir), + {ok, undefined}. + +make_vsn(_AppInfo, _) -> + {plain, "undefined"}. diff --git a/test/rebar_pkg_SUITE.erl b/test/rebar_pkg_SUITE.erl index 9ddd704..62bc4d1 100644 --- a/test/rebar_pkg_SUITE.erl +++ b/test/rebar_pkg_SUITE.erl @@ -4,17 +4,19 @@ -compile(export_all). -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). +-include("rebar.hrl"). --define(bad_etag, "abcdef"). --define(good_etag, "22e1d7387c9085a462340088a2a8ba67"). +-define(bad_etag, <<"abcdef">>). +-define(good_etag, <<"22e1d7387c9085a462340088a2a8ba67">>). +-define(badpkg_checksum, <<"A14E3718B33F8124E98004433193509EC6660F6CA03302657CAB8785751D77A0">>). +-define(badindex_checksum, <<"7B2CBED315C89F3126B5BF553DD7FF0FB5FE94B064888DD1B095CE8BF4B6A16A">>). -define(bad_checksum, <<"D576B442A68C7B92BACDE1EFE9C6E54D8D6C74BDB71D8175B9D3C6EC8C7B62A7">>). --define(good_checksum, <<"1C6CE379D191FBAB41B7905075E0BF87CBBE23C77CECE775C5A0B786B2244C35">>). +-define(good_checksum, <<"12726BDE1F65583A0817A7E8AADCA73F03FD8CB06F01E6CD29117C4A0DA0AFCF">>). -define(BADPKG_ETAG, <<"BADETAG">>). -all() -> [good_uncached, good_cached, badindexchk, badpkg, - badhash_nocache, badhash_cache, - bad_to_good, good_disconnect, bad_disconnect, pkgs_provider, - find_highest_matching]. +all() -> [good_uncached, good_cached, badpkg, badhash_nocache, + badindexchk, badhash_cache, bad_to_good, good_disconnect, + bad_disconnect, pkgs_provider, find_highest_matching]. init_per_suite(Config) -> application:start(meck), @@ -32,10 +34,6 @@ init_per_testcase(pkgs_provider=Name, Config) -> CacheDir = filename:join([CacheRoot, "hex", "com", "test", "packages"]), filelib:ensure_dir(filename:join([CacheDir, "registry"])), ok = ets:tab2file(Tid, filename:join([CacheDir, "registry"])), - meck:new(rebar_packages, [passthrough]), - meck:expect(rebar_packages, registry_dir, fun(_) -> {ok, CacheDir} end), - meck:expect(rebar_packages, package_dir, fun(_) -> {ok, CacheDir} end), - rebar_prv_update:hex_to_index(rebar_state:new()), Config; init_per_testcase(good_uncached=Name, Config0) -> Config = [{good_cache, false}, @@ -89,9 +87,9 @@ init_per_testcase(good_disconnect=Name, Config0) -> | Config0], Config = mock_config(Name, Config1), copy_to_cache(Pkg, Config), - meck:unload(httpc), + %% meck:unload(httpc), meck:new(httpc, [passthrough, unsticky]), - meck:expect(httpc, request, fun(_, _, _, _, _) -> {error, econnrefused} end), + meck:expect(httpc, request, fun(_, _, _, _) -> {error, econnrefused} end), Config; init_per_testcase(bad_disconnect=Name, Config0) -> Pkg = {<<"goodpkg">>, <<"1.0.0">>}, @@ -99,9 +97,9 @@ init_per_testcase(bad_disconnect=Name, Config0) -> {pkg, Pkg} | Config0], Config = mock_config(Name, Config1), - meck:unload(httpc), - meck:new(httpc, [passthrough, unsticky]), - meck:expect(httpc, request, fun(_, _, _, _, _) -> {error, econnrefused} end), + meck:expect(hex_repo, get_tarball, fun(_, _, _) -> + {error, econnrefused} + end), Config; init_per_testcase(Name, Config0) -> Config = [{good_cache, false}, @@ -117,8 +115,8 @@ good_uncached(Config) -> Tmp = ?config(tmp_dir, Config), {Pkg,Vsn} = ?config(pkg, Config), State = ?config(state, Config), - ?assertEqual({ok, true}, - rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)), + ?assertEqual(ok, + rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum, #{}}, State, #{}, true)), Cache = ?config(cache_dir, Config), ?assert(filelib:is_regular(filename:join(Cache, <>))). @@ -130,16 +128,17 @@ good_cached(Config) -> CachedFile = filename:join(Cache, <>), ?assert(filelib:is_regular(CachedFile)), {ok, Content} = file:read_file(CachedFile), - ?assertEqual({ok, true}, - rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)), + ?assertEqual(ok, + rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum, #{}}, State, #{}, true)), {ok, Content} = file:read_file(CachedFile). + badindexchk(Config) -> Tmp = ?config(tmp_dir, Config), {Pkg,Vsn} = ?config(pkg, Config), State = ?config(state, Config), - ?assertMatch({bad_registry_checksum, _Path}, - rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)), + ?assertMatch({error, {rebar_pkg_resource, {bad_registry_checksum, _, _, _, _}}}, + rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?bad_checksum, #{}}, State, #{}, true)), %% The cached file is there for forensic purposes Cache = ?config(cache_dir, Config), ?assert(filelib:is_regular(filename:join(Cache, <>))). @@ -152,8 +151,8 @@ badpkg(Config) -> CachePath = filename:join(Cache, <>), ETagPath = filename:join(Cache, <>), rebar_pkg_resource:store_etag_in_cache(ETagPath, ?BADPKG_ETAG), - ?assertMatch({bad_download, _Path}, - rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State, false)), + ?assertMatch({error, {hex_tarball, {tarball, {checksum_mismatch, _, _}}}}, + rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?badpkg_checksum, #{}}, State, #{}, false)), %% The cached/etag files are there for forensic purposes ?assert(filelib:is_regular(ETagPath)), ?assert(filelib:is_regular(CachePath)). @@ -162,8 +161,8 @@ badhash_nocache(Config) -> Tmp = ?config(tmp_dir, Config), {Pkg,Vsn} = ?config(pkg, Config), State = ?config(state, Config), - ?assertMatch({unexpected_hash, _Path, ?bad_checksum, ?good_checksum}, - rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?bad_checksum}, State)), + ?assertMatch({error, {rebar_pkg_resource, {bad_registry_checksum, _, _, _, _}}}, + rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?bad_checksum, #{}}, State, #{}, true)), %% The cached file is there for forensic purposes Cache = ?config(cache_dir, Config), ?assert(filelib:is_regular(filename:join(Cache, <>))). @@ -176,8 +175,8 @@ badhash_cache(Config) -> CachedFile = filename:join(Cache, <>), ?assert(filelib:is_regular(CachedFile)), {ok, Content} = file:read_file(CachedFile), - ?assertMatch({unexpected_hash, _Path, ?bad_checksum, ?good_checksum}, - rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?bad_checksum}, State)), + ?assertMatch({error, {rebar_pkg_resource, {bad_registry_checksum, _, _, _, _}}}, + rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?bad_checksum, #{}}, State, #{}, true)), %% The cached file is there still, unchanged. ?assert(filelib:is_regular(CachedFile)), ?assertEqual({ok, Content}, file:read_file(CachedFile)). @@ -190,8 +189,8 @@ bad_to_good(Config) -> CachedFile = filename:join(Cache, <>), ?assert(filelib:is_regular(CachedFile)), {ok, Contents} = file:read_file(CachedFile), - ?assertEqual({ok, true}, - rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)), + ?assertEqual(ok, + rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum, #{}}, State, #{}, true)), %% Cache has refreshed ?assert({ok, Contents} =/= file:read_file(CachedFile)). @@ -205,8 +204,8 @@ good_disconnect(Config) -> ?assert(filelib:is_regular(CachedFile)), {ok, Content} = file:read_file(CachedFile), rebar_pkg_resource:store_etag_in_cache(ETagFile, ?BADPKG_ETAG), - ?assertEqual({ok, true}, - rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)), + ?assertEqual(ok, + rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum, #{}}, State, #{}, true)), {ok, Content} = file:read_file(CachedFile). bad_disconnect(Config) -> @@ -214,32 +213,31 @@ bad_disconnect(Config) -> {Pkg,Vsn} = ?config(pkg, Config), State = ?config(state, Config), ?assertEqual({fetch_fail, Pkg, Vsn}, - rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum}, State)). + rebar_pkg_resource:download(Tmp, {pkg, Pkg, Vsn, ?good_checksum, #{}}, State, #{}, true)). pkgs_provider(Config) -> Config1 = rebar_test_utils:init_rebar_state(Config), rebar_test_utils:run_and_check( - Config1, [], ["pkgs"], + Config1, [], ["pkgs", "relx"], {ok, []} ). find_highest_matching(_Config) -> State = rebar_state:new(), - {ok, Vsn} = rebar_packages:find_highest_matching( - <<"test">>, <<"1.0.0">>, <<"goodpkg">>, <<"1.0.0">>, package_index, State), + {ok, Vsn} = rebar_packages:find_highest_matching_( + <<"goodpkg">>, <<"1.0.0">>, #{name => <<"hexpm">>}, ?PACKAGE_TABLE, State), ?assertEqual(<<"1.0.1">>, Vsn), {ok, Vsn1} = rebar_packages:find_highest_matching( - <<"test">>, <<"1.0.0">>, <<"goodpkg">>, <<"1.0">>, package_index, State), + <<"goodpkg">>, <<"1.0">>, #{name => <<"hexpm">>}, ?PACKAGE_TABLE, State), ?assertEqual(<<"1.1.1">>, Vsn1), {ok, Vsn2} = rebar_packages:find_highest_matching( - <<"test">>, <<"1.0.0">>, <<"goodpkg">>, <<"2.0">>, package_index, State), + <<"goodpkg">>, <<"2.0">>, #{name => <<"hexpm">>}, ?PACKAGE_TABLE, State), ?assertEqual(<<"2.0.0">>, Vsn2), %% regression test. ~> constraints higher than the available packages would result %% in returning the first package version instead of 'none'. - ?assertEqual(none, rebar_packages:find_highest_matching(<<"test">>, <<"1.0.0">>, <<"goodpkg">>, - <<"~> 5.0">>, package_index, State)). - + ?assertEqual(none, rebar_packages:find_highest_matching_(<<"goodpkg">>, <<"~> 5.0">>, + #{name => <<"hexpm">>}, ?PACKAGE_TABLE, State)). %%%%%%%%%%%%%%% %%% Helpers %%% @@ -249,35 +247,67 @@ mock_config(Name, Config) -> CacheRoot = filename:join([Priv, "cache", atom_to_list(Name)]), TmpDir = filename:join([Priv, "tmp", atom_to_list(Name)]), Tid = ets:new(registry_table, [public]), - ets:insert_new(Tid, [ - {<<"badindexchk">>,[[<<"1.0.0">>]]}, - {<<"goodpkg">>,[[<<"1.0.0">>, <<"1.0.1">>, <<"1.1.1">>, <<"2.0.0">>]]}, - {<<"badpkg">>,[[<<"1.0.0">>]]}, + AllDeps = [ {{<<"badindexchk">>,<<"1.0.0">>}, [[], ?bad_checksum, [<<"rebar3">>]]}, {{<<"goodpkg">>,<<"1.0.0">>}, [[], ?good_checksum, [<<"rebar3">>]]}, {{<<"goodpkg">>,<<"1.0.1">>}, [[], ?good_checksum, [<<"rebar3">>]]}, {{<<"goodpkg">>,<<"1.1.1">>}, [[], ?good_checksum, [<<"rebar3">>]]}, {{<<"goodpkg">>,<<"2.0.0">>}, [[], ?good_checksum, [<<"rebar3">>]]}, - {{<<"badpkg">>,<<"1.0.0">>}, [[], ?good_checksum, [<<"rebar3">>]]} - ]), + {{<<"badpkg">>,<<"1.0.0">>}, [[], ?badpkg_checksum, [<<"rebar3">>]]} + ], + ets:insert_new(Tid, AllDeps), CacheDir = filename:join([CacheRoot, "hex", "com", "test", "packages"]), filelib:ensure_dir(filename:join([CacheDir, "registry"])), ok = ets:tab2file(Tid, filename:join([CacheDir, "registry"])), + catch ets:delete(?PACKAGE_TABLE), + rebar_packages:new_package_table(), + lists:foreach(fun({{N, Vsn}, [Deps, Checksum, _]}) -> + case ets:member(?PACKAGE_TABLE, {ec_cnv:to_binary(N), Vsn, <<"hexpm">>}) of + false -> + ets:insert(?PACKAGE_TABLE, #package{key={ec_cnv:to_binary(N), Vsn, <<"hexpm">>}, + dependencies=Deps, + retired=false, + checksum=Checksum}); + true -> + ok + end + end, AllDeps), + + + meck:new(hex_repo, [passthrough]), + meck:expect(hex_repo, get_package, + fun(_Config, PkgName) -> + Matches = ets:match_object(Tid, {{PkgName,'_'}, '_'}), + Releases = + [#{checksum => Checksum, + version => Vsn, + dependencies => Deps} || + {{_, Vsn}, [Deps, Checksum, _]} <- Matches], + {ok, {200, #{}, #{releases => Releases}}} + end), + %% The state returns us a fake registry meck:new(rebar_state, [passthrough]), meck:expect(rebar_state, get, fun(_State, rebar_packages_cdn, _Default) -> - "http://test.com/" + "http://test.com/"; + (_, _, Default) -> + Default + end), + meck:expect(rebar_state, resources, + fun(_State) -> + DefaultConfig = hex_core:default_config(), + [rebar_resource_v2:new(pkg, rebar_pkg_resource, + #{repos => [DefaultConfig#{name => <<"hexpm">>}], + base_config => #{}})] end), meck:new(rebar_dir, [passthrough]), meck:expect(rebar_dir, global_cache_dir, fun(_) -> CacheRoot end), - meck:new(rebar_packages, [passthrough]), meck:expect(rebar_packages, registry_dir, fun(_) -> {ok, CacheDir} end), - meck:expect(rebar_packages, package_dir, fun(_) -> {ok, CacheDir} end), - rebar_prv_update:hex_to_index(rebar_state:new()), + meck:expect(rebar_packages, package_dir, fun(_, _) -> {ok, CacheDir} end), meck:new(rebar_prv_update, [passthrough]), meck:expect(rebar_prv_update, do, fun(State) -> {ok, State} end), @@ -285,16 +315,16 @@ mock_config(Name, Config) -> %% Cache fetches are mocked -- we assume the server and clients are %% correctly used. GoodCache = ?config(good_cache, Config), - {Pkg,Vsn} = ?config(pkg, Config), + {Pkg,Vsn} = ?config(pkg, Config), PkgFile = <>, {ok, PkgContents} = file:read_file(filename:join(?config(data_dir, Config), PkgFile)), - meck:new(httpc, [passthrough, unsticky]), - meck:expect(httpc, request, - fun(get, {_Url, _Opts}, _, _, _) when GoodCache -> - {ok, {{Vsn, 304, <<"Not Modified">>}, [{"etag", ?good_etag}], <<>>}}; - (get, {_Url, _Opts}, _, _, _) -> - {ok, {{Vsn, 200, <<"OK">>}, [{"etag", ?good_etag}], PkgContents}} - end), + + meck:expect(hex_repo, get_tarball, fun(_, _, _) when GoodCache -> + {ok, {304, #{<<"etag">> => ?good_etag}, <<>>}}; + (_, _, _) -> + {ok, {200, #{<<"etag">> => ?good_etag}, PkgContents}} + end), + [{cache_root, CacheRoot}, {cache_dir, CacheDir}, {tmp_dir, TmpDir}, diff --git a/test/rebar_pkg_SUITE_data/badindexchk-1.0.0.tar b/test/rebar_pkg_SUITE_data/badindexchk-1.0.0.tar index e5b963f..1765bb3 100644 Binary files a/test/rebar_pkg_SUITE_data/badindexchk-1.0.0.tar and b/test/rebar_pkg_SUITE_data/badindexchk-1.0.0.tar differ diff --git a/test/rebar_pkg_SUITE_data/badpkg-1.0.0.tar b/test/rebar_pkg_SUITE_data/badpkg-1.0.0.tar index 4930cd2..37bb57d 100644 Binary files a/test/rebar_pkg_SUITE_data/badpkg-1.0.0.tar and b/test/rebar_pkg_SUITE_data/badpkg-1.0.0.tar differ diff --git a/test/rebar_pkg_SUITE_data/goodpkg-1.0.0.tar b/test/rebar_pkg_SUITE_data/goodpkg-1.0.0.tar index e5b963f..d0fa4cb 100644 Binary files a/test/rebar_pkg_SUITE_data/goodpkg-1.0.0.tar and b/test/rebar_pkg_SUITE_data/goodpkg-1.0.0.tar differ diff --git a/test/rebar_pkg_alias_SUITE.erl b/test/rebar_pkg_alias_SUITE.erl index 07656d0..d977b64 100644 --- a/test/rebar_pkg_alias_SUITE.erl +++ b/test/rebar_pkg_alias_SUITE.erl @@ -3,44 +3,53 @@ -include_lib("common_test/include/ct.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("kernel/include/file.hrl"). +-include("rebar.hrl"). -all() -> [same_alias, diff_alias, diff_alias_vsn, transitive_alias, - transitive_hash_mismatch]. +all() -> [same_alias, diff_alias, diff_alias_vsn, transitive_alias%% , + %% transitive_hash_mismatch + ]. %% {uuid, {pkg, uuid}} = uuid %% {uuid, {pkg, alias}} = uuid on disk %% another run should yield the same lock file without error init_per_suite(Config) -> - mock_config(?MODULE, Config). + Config. + %% mock_config(?MODULE, Config). end_per_suite(Config) -> - unmock_config(Config). + Config. + %% unmock_config(Config). init_per_testcase(same_alias, Config0) -> + mock_config(?MODULE, Config0), Config = rebar_test_utils:init_rebar_state(Config0,"same_alias_"), AppDir = ?config(apps, Config), rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]), RebarConf = rebar_test_utils:create_config(AppDir, [{deps, [{fakelib, {pkg, fakelib}}]}]), [{rebarconfig, RebarConf} | Config]; init_per_testcase(diff_alias, Config0) -> + mock_config(?MODULE, Config0), Config = rebar_test_utils:init_rebar_state(Config0,"diff_alias_"), AppDir = ?config(apps, Config), rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]), RebarConf = rebar_test_utils:create_config(AppDir, [{deps, [{fakelib, {pkg, goodpkg}}]}]), [{rebarconfig, RebarConf} | Config]; init_per_testcase(diff_alias_vsn, Config0) -> + mock_config(?MODULE, Config0), Config = rebar_test_utils:init_rebar_state(Config0,"diff_alias_vsn_"), AppDir = ?config(apps, Config), rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]), RebarConf = rebar_test_utils:create_config(AppDir, [{deps, [{fakelib, "1.0.0", {pkg, goodpkg}}]}]), [{rebarconfig, RebarConf} | Config]; init_per_testcase(transitive_alias, Config0) -> + mock_config(?MODULE, Config0), Config = rebar_test_utils:init_rebar_state(Config0,"transitive_alias_vsn_"), AppDir = ?config(apps, Config), rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]), RebarConf = rebar_test_utils:create_config(AppDir, [{deps, [{topdep, "1.0.0", {pkg, topdep}}]}]), [{rebarconfig, RebarConf} | Config]; init_per_testcase(transitive_hash_mismatch, Config0) -> + mock_config(?MODULE, Config0), Config = rebar_test_utils:init_rebar_state(Config0,"transitive_alias_vsn_"), AppDir = ?config(apps, Config), rebar_test_utils:create_app(AppDir, "A", "0.0.0", [kernel, stdlib]), @@ -48,6 +57,7 @@ init_per_testcase(transitive_hash_mismatch, Config0) -> [{rebarconfig, RebarConf} | Config]. end_per_testcase(_, Config) -> + unmock_config(Config), Config. same_alias(Config) -> @@ -162,6 +172,10 @@ transitive_hash_mismatch(Config) -> ), ok. +parse_deps(Deps) -> + [{maps:get(app, D, Name), {pkg, Name, Constraint, undefined}} || D=#{package := Name, + requirement := Constraint} <- Deps]. + mock_config(Name, Config) -> {ChkFake, Etag} = create_lib(Name, Config, "fakelib"), {ChkTop, _} = create_lib(Name, Config, "topdep"), @@ -176,40 +190,74 @@ mock_config(Name, Config) -> CacheDir = filename:join([CacheRoot, "hex", "com", "test", "packages"]), rebar_test_utils:create_app(AppDir, "fakelib", "1.0.0", [kernel, stdlib]), ct:pal("{~p, ~p}",[ChkFake, Etag]), - {ChkFake, Etag} = rebar_test_utils:package_app(AppDir, CacheDir, "goodpkg-1.0.0"), + {ChkGood, EtagGood} = rebar_test_utils:package_app(AppDir, CacheDir, "goodpkg", "1.0.0"), + AllDeps = [ + {<<"fakelib">>,[[<<"1.0.0">>]]}, + {<<"goodpkg">>,[[<<"1.0.0">>]]}, + {<<"topdep">>,[[<<"1.0.0">>]]}, + {<<"transitive">>, [[<<"1.0.0">>]]}, + {{<<"fakelib">>,<<"1.0.0">>}, [[], ChkFake, [<<"rebar3">>]]}, + {{<<"goodpkg">>,<<"1.0.0">>}, [[], ChkGood, [<<"rebar3">>]]}, + {{<<"topdep">>,<<"1.0.0">>}, + [[ + {<<"transitive">>, <<"1.0.0">>, false, <<"transitive_app">>} + ], ChkTop, [<<"rebar3">>]]}, + {{<<"transitive">>,<<"1.0.0">>}, [[], ChkTrans, [<<"rebar3">>]]} + ], Tid = ets:new(registry_table, [public]), - ets:insert_new(Tid, [ - {<<"fakelib">>,[[<<"1.0.0">>]]}, - {<<"goodpkg">>,[[<<"1.0.0">>]]}, - {<<"topdep">>,[[<<"1.0.0">>]]}, - {<<"transitive">>, [[<<"1.0.0">>]]}, - {{<<"fakelib">>,<<"1.0.0">>}, [[], ChkFake, [<<"rebar3">>]]}, - {{<<"goodpkg">>,<<"1.0.0">>}, [[], ChkFake, [<<"rebar3">>]]}, - {{<<"topdep">>,<<"1.0.0">>}, - [[ - [<<"transitive">>, <<"1.0.0">>, false, <<"transitive_app">>] - ], ChkTop, [<<"rebar3">>]]}, - {{<<"transitive">>,<<"1.0.0">>}, [[], ChkTrans, [<<"rebar3">>]]} - ]), + ets:insert_new(Tid, AllDeps), ok = ets:tab2file(Tid, filename:join([CacheDir, "registry"])), - ets:delete(Tid), + %% ets:delete(Tid), %% The state returns us a fake registry meck:new(rebar_dir, [passthrough, no_link]), meck:expect(rebar_dir, global_cache_dir, fun(_) -> CacheRoot end), meck:new(rebar_packages, [passthrough, no_link]), meck:expect(rebar_packages, registry_dir, fun(_) -> {ok, CacheDir} end), - meck:expect(rebar_packages, package_dir, fun(_) -> {ok, CacheDir} end), - rebar_prv_update:hex_to_index(rebar_state:new()), - - %% Cache fetches are mocked -- we assume the server and clients are - %% correctly used. - meck:new(httpc, [passthrough, unsticky, no_link]), - meck:expect(httpc, request, - fun(get, {_Url, _Opts}, _, _, _) -> - {ok, {{<<"1.0.0">>, 304, <<"Not Modified">>}, [{"etag", Etag}], <<>>}} - end), + meck:expect(rebar_packages, package_dir, fun(_, _) -> {ok, CacheDir} end), + + %% TODO: is something else wrong that we need this for transitive_alias to pass + meck:expect(rebar_packages, update_package, fun(_, _, _) -> ok end), + + meck:new(rebar_prv_update, [passthrough]), + meck:expect(rebar_prv_update, do, fun(State) -> {ok, State} end), + + catch ets:delete(?PACKAGE_TABLE), + rebar_packages:new_package_table(), + + lists:foreach(fun({{N, Vsn}, [Deps, Checksum, _]}) -> + case ets:member(?PACKAGE_TABLE, {ec_cnv:to_binary(N), Vsn, <<"hexpm">>}) of + false -> + ets:insert(?PACKAGE_TABLE, #package{key={ec_cnv:to_binary(N), Vsn, <<"hexpm">>}, + dependencies=[{DAppName, {pkg, DN, DV, undefined}} || {DN, DV, _, DAppName} <- Deps], + retired=false, + checksum=Checksum}); + true -> + ok + end; + ({_N, _Vsns}) -> + ok + + end, AllDeps), + + meck:new(hex_repo, [passthrough]), + meck:expect(hex_repo, get_package, + fun(_Config, PkgName) -> + Matches = ets:match_object(Tid, {{PkgName,'_'}, '_'}), + Releases = + [#{checksum => Checksum, + version => Vsn, + dependencies => [{DAppName, {pkg, DN, DV, undefined}} || + {DN, DV, _, DAppName} <- Deps]} || + {{_, Vsn}, [Deps, Checksum, _]} <- Matches], + {ok, {200, #{}, #{releases => Releases}}} + end), + + meck:expect(hex_repo, get_tarball, fun(_, _, _) -> + {ok, {304, #{<<"etag">> => EtagGood}, <<>>}} + end), + %% Move all packages to cache NewConf = [{cache_root, CacheRoot}, {cache_dir, CacheDir}, @@ -231,4 +279,4 @@ create_lib(Name, Config, AppName, PkgName) -> CacheDir = filename:join([CacheRoot, "hex", "com", "test", "packages"]), filelib:ensure_dir(filename:join([CacheDir, "registry"])), rebar_test_utils:create_app(AppDir, AppName, "1.0.0", [kernel, stdlib]), - rebar_test_utils:package_app(AppDir, CacheDir, PkgName++"-1.0.0"). + rebar_test_utils:package_app(AppDir, CacheDir, PkgName, "1.0.0"). diff --git a/test/rebar_pkg_repos_SUITE.erl b/test/rebar_pkg_repos_SUITE.erl new file mode 100644 index 0000000..601566e --- /dev/null +++ b/test/rebar_pkg_repos_SUITE.erl @@ -0,0 +1,331 @@ +%% Test suite for the handling hexpm repo configurations +-module(rebar_pkg_repos_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("eunit/include/eunit.hrl"). +-include("rebar.hrl"). + +all() -> + [default_repo, repo_merging, repo_replacing, + auth_merging, organization_merging, {group, resolve_version}]. + +groups() -> + [{resolve_version, [use_first_repo_match, use_exact_with_hash, fail_repo_update, + ignore_match_in_excluded_repo]}]. + +init_per_group(resolve_version, Config) -> + Repo1 = <<"test-repo-1">>, + Repo2 = <<"test-repo-2">>, + Repo3 = <<"test-repo-3">>, + Hexpm = <<"hexpm">>, + Repos = [Repo1, Repo2, Repo3, Hexpm], + + Deps = [{"A", "0.1.1", <<"good checksum">>, Repo1}, + {"A", "0.1.1", <<"good checksum">>, Repo2}, + {"B", "1.0.0", Repo1}, + {"B", "2.0.0", Repo2}, + {"B", "1.4.0", Repo3}, + {"B", "1.4.3", Hexpm}, + {"C", "1.3.1", <<"bad checksum">>, Repo1}, + {"C", "1.3.1", <<"good checksum">>, Repo2}], + [{deps, Deps}, {repos, Repos} | Config]; +init_per_group(_, Config) -> + Config. + +end_per_group(_, _) -> + ok. + +init_per_testcase(use_first_repo_match, Config) -> + Deps = ?config(deps, Config), + Repos = ?config(repos, Config), + State = setup_deps_and_repos(Deps, Repos), + + meck:new(rebar_packages, [passthrough, no_link]), + + %% fail when the first repo is updated since it doesn't have a matching package + %% should continue anyway + meck:expect(rebar_packages, update_package, + fun(_, _, _State) -> ok end), + meck:expect(rebar_packages, verify_table, + fun(_State) -> true end), + + [{state, State} | Config]; +init_per_testcase(use_exact_with_hash, Config) -> + Deps = ?config(deps, Config), + Repos = ?config(repos, Config), + State = setup_deps_and_repos(Deps, Repos), + + meck:new(rebar_packages, [passthrough, no_link]), + + %% fail when the first repo is updated since it doesn't have a matching package + %% should continue anyway + meck:expect(rebar_packages, update_package, + fun(_, _, _State) -> ok end), + meck:expect(rebar_packages, verify_table, + fun(_State) -> true end), + + [{state, State} | Config]; +init_per_testcase(fail_repo_update, Config) -> + Deps = ?config(deps, Config), + Repos = ?config(repos, Config), + State = setup_deps_and_repos(Deps, Repos), + + meck:new(rebar_packages, [passthrough, no_link]), + + %% fail when the first repo is updated since it doesn't have a matching package + %% should continue anyway + [Repo1 | _] = Repos, + meck:expect(rebar_packages, update_package, + fun(_, #{name := Repo}, _State) when Repo =:= Repo1 -> fail; + (_, _, _State) -> ok end), + meck:expect(rebar_packages, verify_table, + fun(_State) -> true end), + + [{state, State} | Config]; +init_per_testcase(ignore_match_in_excluded_repo, Config) -> + Deps = ?config(deps, Config), + Repos = [Repo1, _, Repo3 | _] = ?config(repos, Config), + + %% drop repo1 and repo2 from the repos to be used by the pkg resource + State = setup_deps_and_repos(Deps, [R || R <- Repos, R =/= Repo3, R =/= Repo1]), + + meck:new(rebar_packages, [passthrough, no_link]), + + %% fail when the first repo is updated since it doesn't have a matching package + %% should continue anyway + [_, _, Repo3 | _] = Repos, + meck:expect(rebar_packages, update_package, + fun(_, _, _State) -> ok end), + meck:expect(rebar_packages, verify_table, + fun(_State) -> true end), + + [{state, State} | Config]; +init_per_testcase(auth_merging, Config) -> + meck:new(file, [passthrough, no_link, unstick]), + meck:new(rebar_packages, [passthrough, no_link]), + Config; +init_per_testcase(organization_merging, Config) -> + meck:new(file, [passthrough, no_link, unstick]), + meck:new(rebar_packages, [passthrough, no_link]), + Config; +init_per_testcase(_, Config) -> + Config. + +end_per_testcase(Case, _Config) when Case =:= auth_merging ; + Case =:= organization_merging -> + meck:unload(file), + meck:unload(rebar_packages); +end_per_testcase(Case, _Config) when Case =:= use_first_repo_match ; + Case =:= use_exact_with_hash ; + Case =:= fail_repo_update ; + Case =:= ignore_match_in_excluded_repo -> + meck:unload(rebar_packages); +end_per_testcase(_, _) -> + ok. + + +default_repo(_Config) -> + Repo1 = #{name => <<"hexpm">>, + api_key => <<"asdf">>}, + + MergedRepos = rebar_hex_repos:repos([{repos, [Repo1]}]), + + ?assertMatch([#{name := <<"hexpm">>, + api_key := <<"asdf">>, + api_url := <<"https://hex.pm/api">>}], MergedRepos). + + +repo_merging(_Config) -> + Repo1 = #{name => <<"repo-1">>, + api_url => <<"repo-1/api">>}, + Repo2 = #{name => <<"repo-2">>, + repo_url => <<"repo-2/repo">>, + repo_verify => false}, + Result = rebar_hex_repos:merge_repos([Repo1, Repo2, + #{name => <<"repo-2">>, + api_url => <<"repo-2/api">>, + repo_url => <<"bad url">>, + repo_verify => true}, + #{name => <<"repo-1">>, + api_url => <<"bad url">>, + repo_verify => true}, + #{name => <<"repo-2">>, + api_url => <<"repo-2/api-2">>, + repo_url => <<"other/repo">>}]), + ?assertMatch([#{name := <<"repo-1">>, + api_url := <<"repo-1/api">>, + repo_verify := true}, + #{name := <<"repo-2">>, + api_url := <<"repo-2/api">>, + repo_url := <<"repo-2/repo">>, + repo_verify := false}], Result). + +repo_replacing(_Config) -> + Repo1 = #{name => <<"repo-1">>, + api_url => <<"repo-1/api">>}, + Repo2 = #{name => <<"repo-2">>, + repo_url => <<"repo-2/repo">>, + repo_verify => false}, + + ?assertMatch([Repo1, Repo2, #{name := <<"hexpm">>}], + rebar_hex_repos:repos([{repos, [Repo1]}, + {repos, [Repo2]}])), + + %% use of replace is ignored if found in later entries than the first + ?assertMatch([Repo1, Repo2, #{name := <<"hexpm">>}], + rebar_hex_repos:repos([{repos, [Repo1]}, + {repos, replace, [Repo2]}])), + + ?assertMatch([Repo1], + rebar_hex_repos:repos([{repos, replace, [Repo1]}, + {repos, [Repo2]}])). + +auth_merging(_Config) -> + Repo1 = #{name => <<"repo-1">>, + api_url => <<"repo-1/api">>}, + Repo2 = #{name => <<"repo-2">>, + repo_url => <<"repo-2/repo">>, + repo_verify => false}, + + State = rebar_state:new([{hex, [{repos, [Repo1, Repo2]}]}]), + meck:expect(file, consult, + fun(_) -> + {ok, [#{<<"repo-1">> => #{read_key => <<"read key">>, + write_key => <<"write key">>}, + <<"repo-2">> => #{read_key => <<"read key 2">>, + repos_key => <<"repos key 2">>, + write_key => <<"write key 2">>}, + <<"hexpm">> => #{write_key => <<"write key hexpm">>}}]} + end), + + ?assertMatch({ok, + #resource{state=#{repos := [#{name := <<"repo-1">>, + read_key := <<"read key">>, + write_key := <<"write key">>}, + #{name := <<"repo-2">>, + read_key := <<"read key 2">>, + repos_key := <<"repos key 2">>, + write_key := <<"write key 2">>}, + #{name := <<"hexpm">>, + write_key := <<"write key hexpm">>}]}}}, + rebar_pkg_resource:init(pkg, State)), + + ok. + +organization_merging(_Config) -> + Repo1 = #{name => <<"hexpm:repo-1">>, + api_url => <<"repo-1/api">>}, + Repo2 = #{name => <<"hexpm:repo-2">>, + repo_url => <<"repo-2/repo">>, + repo_verify => false}, + + State = rebar_state:new([{hex, [{repos, [Repo1, Repo2]}]}]), + meck:expect(file, consult, + fun(_) -> + {ok, [#{<<"hexpm:repo-1">> => #{read_key => <<"read key">>}, + <<"hexpm:repo-2">> => #{read_key => <<"read key 2">>, + repos_key => <<"repos key 2">>, + write_key => <<"write key 2">>}, + <<"hexpm">> => #{write_key => <<"write key hexpm">>}}]} + end), + + ?assertMatch({ok, + #resource{state=#{repos := [#{name := <<"hexpm:repo-1">>, + parent := <<"hexpm">>, + read_key := <<"read key">>, + write_key := <<"write key hexpm">>}, + #{name := <<"hexpm:repo-2">>, + parent := <<"hexpm">>, + read_key := <<"read key 2">>, + repos_key := <<"repos key 2">>, + write_key := <<"write key 2">>}, + #{name := <<"hexpm">>, + write_key := <<"write key hexpm">>}]}}}, + rebar_pkg_resource:init(pkg, State)), + + ok. + +use_first_repo_match(Config) -> + State = ?config(state, Config), + + ?assertMatch({ok,{package,{<<"B">>, <<"2.0.0">>, Repo2}, + <<"some checksum">>, false, []}, + #{name := Repo2, + http_adapter_config := #{profile := rebar}}}, + rebar_packages:resolve_version(<<"B">>, <<"> 1.4.0">>, undefined, + ?PACKAGE_TABLE, State)), + + ?assertMatch({ok,{package,{<<"B">>, <<"1.4.0">>, Repo3}, + <<"some checksum">>, false, []}, + #{name := Repo3, + http_adapter_config := #{profile := rebar}}}, + rebar_packages:resolve_version(<<"B">>, <<"~> 1.4.0">>, undefined, + ?PACKAGE_TABLE, State)). + +%% tests that even though an easier repo has C-1.3.1 it doesn't use it since its hash is different +use_exact_with_hash(Config) -> + State = ?config(state, Config), + + ?assertMatch({ok,{package,{<<"C">>, <<"1.3.1">>, Repo2}, + <<"good checksum">>, false, []}, + #{name := Repo2, + http_adapter_config := #{profile := rebar}}}, + rebar_packages:resolve_version(<<"C">>, <<"1.3.1">>, <<"good checksum">>, + ?PACKAGE_TABLE, State)). + +fail_repo_update(Config) -> + State = ?config(state, Config), + + ?assertMatch({ok,{package,{<<"B">>, <<"1.4.0">>, Repo3}, + <<"some checksum">>, false, []}, + #{name := Repo3, + http_adapter_config := #{profile := rebar}}}, + rebar_packages:resolve_version(<<"B">>, <<"~> 1.4.0">>, undefined, + ?PACKAGE_TABLE, State)). + +ignore_match_in_excluded_repo(Config) -> + State = ?config(state, Config), + Repos = ?config(repos, Config), + + ?assertMatch({ok,{package,{<<"B">>, <<"1.4.3">>, Hexpm}, + <<"some checksum">>, false, []}, + #{name := Hexpm, + http_adapter_config := #{profile := rebar}}}, + rebar_packages:resolve_version(<<"B">>, <<"~> 1.4.0">>, undefined, + ?PACKAGE_TABLE, State)), + + [_, Repo2 | _] = Repos, + ?assertMatch({ok,{package,{<<"A">>, <<"0.1.1">>, Repo2}, + <<"good checksum">>, false, []}, + #{name := Repo2, + http_adapter_config := #{profile := rebar}}}, + rebar_packages:resolve_version(<<"A">>, <<"0.1.1">>, <<"good checksum">>, + ?PACKAGE_TABLE, State)). + +%% + +setup_deps_and_repos(Deps, Repos) -> + true = rebar_packages:new_package_table(), + insert_deps(Deps), + State = rebar_state:new([{hex, [{repos, [#{name => R} || R <- Repos]}]}]), + rebar_state:create_resources([{pkg, rebar_pkg_resource}], State). + + +insert_deps(Deps) -> + lists:foreach(fun({Name, Version, Repo}) -> + ets:insert(?PACKAGE_TABLE, #package{key={rebar_utils:to_binary(Name), + rebar_utils:to_binary(Version), + rebar_utils:to_binary(Repo)}, + dependencies=[], + retired=false, + checksum = <<"some checksum">>}); + ({Name, Version, Checksum, Repo}) -> + ets:insert(?PACKAGE_TABLE, #package{key={rebar_utils:to_binary(Name), + rebar_utils:to_binary(Version), + rebar_utils:to_binary(Repo)}, + dependencies=[], + retired=false, + checksum = Checksum}) + end, Deps). diff --git a/test/rebar_resource_SUITE.erl b/test/rebar_resource_SUITE.erl index 15f14db..ddacb91 100644 --- a/test/rebar_resource_SUITE.erl +++ b/test/rebar_resource_SUITE.erl @@ -29,12 +29,15 @@ init_per_testcase(change_type_upgrade, Config) -> TypeStr = atom_to_list(Type), DirName = filename:join([?config(priv_dir, Config), "resource_"++TypeStr]), ec_file:mkdir_path(DirName), - [{path, DirName} | Config]. + + {ok, AppInfo} = rebar_app_info:new(test_app, "0.0.1", DirName), + AppInfo1 = rebar_app_info:source(AppInfo, ?config(resource, Config)), + + [{app, AppInfo1} | Config]. end_per_testcase(_, Config) -> Config. change_type_upgrade(Config) -> - ?assert(rebar_fetch:needs_update(?config(path, Config), - ?config(resource, Config), + ?assert(rebar_fetch:needs_update(?config(app, Config), ?config(state, Config))). diff --git a/test/rebar_test_utils.erl b/test/rebar_test_utils.erl index b74aa2f..8bcb6d1 100644 --- a/test/rebar_test_utils.erl +++ b/test/rebar_test_utils.erl @@ -4,8 +4,9 @@ -export([init_rebar_state/1, init_rebar_state/2, run_and_check/4, check_results/3]). -export([expand_deps/2, flat_deps/1, top_level_deps/1]). -export([create_app/4, create_plugin/4, create_eunit_app/4, create_empty_app/4, - create_config/2, create_config/3, package_app/3]). --export([create_random_name/1, create_random_vsn/0, write_src_file/2]). + create_config/2, create_config/3, package_app/4]). +-export([create_random_name/1, create_random_vsn/0, write_src_file/2, + random_element/1]). %% Pick the right random module -ifdef(rand_only). @@ -34,8 +35,10 @@ init_rebar_state(Config, Name) -> Verbosity = rebar3:log_level(), rebar_log:init(command_line, Verbosity), GlobalDir = filename:join([DataDir, "cache"]), + Repos = proplists:get_value(repos, Config, []), State = rebar_state:new([{base_dir, filename:join([AppsDir, "_build"])} ,{global_rebar_dir, GlobalDir} + ,{hex, [{repos, [#{name => R} || R <- Repos]}]} ,{root_dir, AppsDir}]), [{apps, AppsDir}, {checkouts, CheckoutsDir}, {state, State} | Config]. @@ -467,24 +470,25 @@ get_app_metadata(Name, Vsn, Deps) -> {registered, []}, {applications, Deps}]}. -package_app(AppDir, DestDir, PkgName) -> - Name = PkgName++".tar", - {ok, Fs} = rebar_utils:list_dir(AppDir), - ok = erl_tar:create(filename:join(DestDir, "contents.tar.gz"), - lists:zip(Fs, [filename:join(AppDir,F) || F <- Fs]), - [compressed]), - ok = file:write_file(filename:join(DestDir, "metadata.config"), "who cares"), - ok = file:write_file(filename:join(DestDir, "VERSION"), "3"), - {ok, Contents} = file:read_file(filename:join(DestDir, "contents.tar.gz")), - Blob = <<"3who cares", Contents/binary>>, - <> = crypto:hash(sha256, Blob), - BinChecksum = list_to_binary(rebar_string:uppercase(lists:flatten(io_lib:format("~64.16.0b", [X])))), - ok = file:write_file(filename:join(DestDir, "CHECKSUM"), BinChecksum), - PkgFiles = ["contents.tar.gz", "VERSION", "metadata.config", "CHECKSUM"], +package_app(AppDir, DestDir, PkgName, PkgVsn) -> + AppSrc = filename:join(AppDir, "src"), + {ok, Fs} = rebar_utils:list_dir(AppSrc), + Files = lists:zip([filename:join("src", F) || F <- Fs], [filename:join(AppSrc,F) || F <- Fs]), + Metadata = #{<<"app">> => list_to_binary(PkgName), + <<"version">> => list_to_binary(PkgVsn)}, + {ok, {Tarball, <>}} = hex_tarball:create(Metadata, Files), + + Name = PkgName++"-"++PkgVsn++".tar", Archive = filename:join(DestDir, Name), - ok = erl_tar:create(Archive, - lists:zip(PkgFiles, [filename:join(DestDir,F) || F <- PkgFiles])), - {ok, BinFull} = file:read_file(Archive), - <> = crypto:hash(md5, BinFull), - Etag = rebar_string:lowercase(lists:flatten(io_lib:format("~32.16.0b", [E]))), - {BinChecksum, Etag}. + file:write_file(Archive, Tarball), + + <> = crypto:hash(md5, Tarball), + + Checksum1 = list_to_binary( + rebar_string:uppercase( + lists:flatten(io_lib:format("~64.16.0b", [Checksum])))), + {Checksum1, E}. + +random_element(Repos) -> + Index = ?random:uniform(length(Repos)), + lists:nth(Index, Repos). diff --git a/test/rebar_upgrade_SUITE.erl b/test/rebar_upgrade_SUITE.erl index 45a7433..c55456c 100644 --- a/test/rebar_upgrade_SUITE.erl +++ b/test/rebar_upgrade_SUITE.erl @@ -112,25 +112,25 @@ setup_project(Case, Config0, Deps, UpDeps) -> upgrades(top_a) -> %% Original tree - {[{"A", "1", [{"B", [{"D", "1", []}]}, - {"C", [{"D", "2", []}]}]} + {[{"A", "1.0.0", [{"B", [{"D", "1.0.0", []}]}, + {"C", [{"D", "2.0.0", []}]}]} ], %% Updated tree - [{"A", "1", [{"B", [{"D", "3", []}]}, - {"C", [{"D", "2", []}]}]} + [{"A", "1.0.0", [{"B", [{"D", "3.0.0", []}]}, + {"C", [{"D", "2.0.0", []}]}]} ], %% Modified apps, gobally ["A","B","D"], %% upgrade vs. new tree - {"A", [{"A","1"}, "B", "C", {"D","3"}]}}; + {"A", [{"A","1.0.0"}, "B", "C", {"D","3.0.0"}]}}; upgrades(top_b) -> %% Original tree - {[{"A", "1", [{"B", [{"D", "1", []}]}, - {"C", [{"D", "2", []}]}]} + {[{"A", "1.0.0", [{"B", [{"D", "1.0.0", []}]}, + {"C", [{"D", "2.0.0", []}]}]} ], %% Updated tree - [{"A", "1", [{"B", [{"D", "3", []}]}, - {"C", [{"D", "2", []}]}]} + [{"A", "1.0.0", [{"B", [{"D", "3.0.0", []}]}, + {"C", [{"D", "2.0.0", []}]}]} ], %% Modified apps, gobally ["A","B","D"], @@ -138,12 +138,12 @@ upgrades(top_b) -> {"B", {error, {rebar_prv_upgrade, {transitive_dependency, <<"B">>}}}}}; upgrades(top_c) -> %% Original tree - {[{"A", "1", [{"B", [{"D", "1", []}]}, - {"C", [{"D", "2", []}]}]} + {[{"A", "1.0.0", [{"B", [{"D", "1.0.0", []}]}, + {"C", [{"D", "2.0.0", []}]}]} ], %% Updated tree - [{"A", "1", [{"B", [{"D", "3", []}]}, - {"C", [{"D", "2", []}]}]} + [{"A", "1.0.0", [{"B", [{"D", "3.0.0", []}]}, + {"C", [{"D", "2.0.0", []}]}]} ], %% Modified apps, gobally ["A","B","D"], @@ -151,12 +151,12 @@ upgrades(top_c) -> {"C", {error, {rebar_prv_upgrade, {transitive_dependency, <<"C">>}}}}}; upgrades(top_d1) -> %% Original tree - {[{"A", "1", [{"B", [{"D", "1", []}]}, - {"C", [{"D", "2", []}]}]} + {[{"A", "1.0.0", [{"B", [{"D", "1.0.0", []}]}, + {"C", [{"D", "2.0.0", []}]}]} ], %% Updated tree - [{"A", "1", [{"B", [{"D", "3", []}]}, - {"C", [{"D", "2", []}]}]} + [{"A", "1.0.0", [{"B", [{"D", "3.0.0", []}]}, + {"C", [{"D", "2.0.0", []}]}]} ], %% Modified apps, gobally ["A","B","D"], @@ -164,12 +164,12 @@ upgrades(top_d1) -> {"D", {error, {rebar_prv_upgrade, {transitive_dependency, <<"D">>}}}}}; upgrades(top_d2) -> %% Original tree - {[{"A", "1", [{"B", [{"D", "1", []}]}, - {"C", [{"D", "2", []}]}]} + {[{"A", "1.0.0", [{"B", [{"D", "1.0.0", []}]}, + {"C", [{"D", "2.0.0", []}]}]} ], %% Updated tree - [{"A", "1", [{"B", [{"D", "3", []}]}, - {"C", [{"D", "2", []}]}]} + [{"A", "1.0.0", [{"B", [{"D", "3.0.0", []}]}, + {"C", [{"D", "2.0.0", []}]}]} ], %% Modified apps, gobally ["A","B","D"], @@ -177,342 +177,342 @@ upgrades(top_d2) -> {"D", {error, {rebar_prv_upgrade, {transitive_dependency, <<"D">>}}}}}; upgrades(top_e) -> %% Original tree - {[{"A", "1", [{"B", [{"D", "1", []}]}, - {"C", [{"D", "2", []}]}]} + {[{"A", "1.0.0", [{"B", [{"D", "1.0.0", []}]}, + {"C", [{"D", "2.0.0", []}]}]} ], %% Updated tree - [{"A", "1", [{"B", [{"D", "3", []}]}, - {"C", [{"D", "2", []}]}]} + [{"A", "1.0.0", [{"B", [{"D", "3.0.0", []}]}, + {"C", [{"D", "2.0.0", []}]}]} ], %% Modified apps, gobally ["A","B","D"], %% upgrade vs. new tree {"E", {error, {rebar_prv_upgrade, {unknown_dependency, <<"E">>}}}}}; upgrades(pair_a) -> - {[{"A", "1", [{"C", "1", []}]}, - {"B", "1", [{"D", "1", []}]} + {[{"A", "1.0.0", [{"C", "1.0.0", []}]}, + {"B", "1.0.0", [{"D", "1.0.0", []}]} ], - [{"A", "2", [{"C", "2", []}]}, - {"B", "2", [{"D", "2", []}]} + [{"A", "2.0.0", [{"C", "2.0.0", []}]}, + {"B", "2.0.0", [{"D", "2.0.0", []}]} ], ["A","B","C","D"], - {"A", [{"A","2"},{"C","2"},{"B","1"},{"D","1"}]}}; + {"A", [{"A","2.0.0"},{"C","2.0.0"},{"B","1.0.0"},{"D","1.0.0"}]}}; upgrades(pair_b) -> - {[{"A", "1", [{"C", "1", []}]}, - {"B", "1", [{"D", "1", []}]} + {[{"A", "1.0.0", [{"C", "1.0.0", []}]}, + {"B", "1.0.0", [{"D", "1.0.0", []}]} ], - [{"A", "2", [{"C", "2", []}]}, - {"B", "2", [{"D", "2", []}]} + [{"A", "2.0.0", [{"C", "2.0.0", []}]}, + {"B", "2.0.0", [{"D", "2.0.0", []}]} ], ["A","B","C","D"], - {"B", [{"A","1"},{"C","1"},{"B","2"},{"D","2"}]}}; + {"B", [{"A","1.0.0"},{"C","1.0.0"},{"B","2.0.0"},{"D","2.0.0"}]}}; upgrades(pair_ab) -> - {[{"A", "1", [{"C", "1", []}]}, - {"B", "1", [{"D", "1", []}]} + {[{"A", "1.0.0", [{"C", "1.0.0", []}]}, + {"B", "1.0.0", [{"D", "1.0.0", []}]} ], - [{"A", "2", [{"C", "2", []}]}, - {"B", "2", [{"D", "2", []}]} + [{"A", "2.0.0", [{"C", "2.0.0", []}]}, + {"B", "2.0.0", [{"D", "2.0.0", []}]} ], ["A","B","C","D"], - {"A,B", [{"A","2"},{"C","2"},{"B","2"},{"D","2"}]}}; + {"A,B", [{"A","2.0.0"},{"C","2.0.0"},{"B","2.0.0"},{"D","2.0.0"}]}}; upgrades(pair_c) -> - {[{"A", "1", [{"C", "1", []}]}, - {"B", "1", [{"D", "1", []}]} + {[{"A", "1.0.0", [{"C", "1.0.0", []}]}, + {"B", "1.0.0", [{"D", "1.0.0", []}]} ], - [{"A", "2", [{"C", "2", []}]}, - {"B", "2", [{"D", "2", []}]} + [{"A", "2.0.0", [{"C", "2.0.0", []}]}, + {"B", "2.0.0", [{"D", "2.0.0", []}]} ], ["A","B","C","D"], {"C", {error, {rebar_prv_upgrade, {transitive_dependency, <<"C">>}}}}}; upgrades(pair_all) -> - {[{"A", "1", [{"C", "1", []}]}, - {"B", "1", [{"D", "1", []}]} + {[{"A", "1.0.0", [{"C", "1.0.0", []}]}, + {"B", "1.0.0", [{"D", "1.0.0", []}]} ], - [{"A", "2", [{"C", "2", []}]}, - {"B", "2", [{"D", "2", []}]} + [{"A", "2.0.0", [{"C", "2.0.0", []}]}, + {"B", "2.0.0", [{"D", "2.0.0", []}]} ], ["A","B","C","D"], - {"", [{"A","2"},{"C","2"},{"B","2"},{"D","2"}]}}; + {"", [{"A","2.0.0"},{"C","2.0.0"},{"B","2.0.0"},{"D","2.0.0"}]}}; upgrades(triplet_a) -> - {[{"A", "1", [{"D",[]}, - {"E","3",[]}]}, - {"B", "1", [{"F","1",[]}, + {[{"A", "1.0.0", [{"D",[]}, + {"E","3.0.0",[]}]}, + {"B", "1.0.0", [{"F","1.0.0",[]}, {"G",[]}]}, - {"C", "0", [{"H","3",[]}, + {"C", "0.0.0", [{"H","3.0.0",[]}, {"I",[]}]}], - [{"A", "1", [{"D",[]}, - {"E","2",[]}]}, - {"B", "1", [{"F","1",[]}, + [{"A", "1.0.0", [{"D",[]}, + {"E","2.0.0",[]}]}, + {"B", "1.0.0", [{"F","1.0.0",[]}, {"G",[]}]}, - {"C", "1", [{"H","4",[]}, + {"C", "1.0.0", [{"H","4.0.0",[]}, {"I",[]}]}], ["A","C","E","H"], - {"A", [{"A","1"}, "D", {"E","2"}, - {"B","1"}, {"F","1"}, "G", - {"C","0"}, {"H","3"}, "I"]}}; + {"A", [{"A","1.0.0"}, "D", {"E","2.0.0"}, + {"B","1.0.0"}, {"F","1.0.0"}, "G", + {"C","0.0.0"}, {"H","3.0.0"}, "I"]}}; upgrades(triplet_b) -> - {[{"A", "1", [{"D",[]}, - {"E","3",[]}]}, - {"B", "1", [{"F","1",[]}, + {[{"A", "1.0.0", [{"D",[]}, + {"E","3.0.0",[]}]}, + {"B", "1.0.0", [{"F","1.0.0",[]}, {"G",[]}]}, - {"C", "0", [{"H","3",[]}, + {"C", "0.0.0", [{"H","3.0.0",[]}, {"I",[]}]}], - [{"A", "2", [{"D",[]}, - {"E","2",[]}]}, - {"B", "1", [{"F","1",[]}, + [{"A", "2.0.0", [{"D",[]}, + {"E","2.0.0",[]}]}, + {"B", "1.0.0", [{"F","1.0.0",[]}, {"G",[]}]}, - {"C", "1", [{"H","4",[]}, + {"C", "1.0.0", [{"H","4.0.0",[]}, {"I",[]}]}], ["A","C","E","H"], - {"B", [{"A","1"}, "D", {"E","3"}, - {"B","1"}, {"F","1"}, "G", - {"C","0"}, {"H","3"}, "I"]}}; + {"B", [{"A","1.0.0"}, "D", {"E","3.0.0"}, + {"B","1.0.0"}, {"F","1.0.0"}, "G", + {"C","0.0.0"}, {"H","3.0.0"}, "I"]}}; upgrades(triplet_c) -> - {[{"A", "1", [{"D",[]}, - {"E","3",[]}]}, - {"B", "1", [{"F","1",[]}, + {[{"A", "1.0.0", [{"D",[]}, + {"E","3.0.0",[]}]}, + {"B", "1.0.0", [{"F","1.0.0",[]}, {"G",[]}]}, - {"C", "0", [{"H","3",[]}, + {"C", "0.0.0", [{"H","3.0.0",[]}, {"I",[]}]}], - [{"A", "2", [{"D",[]}, - {"E","2",[]}]}, - {"B", "1", [{"F","1",[]}, + [{"A", "2.0.0", [{"D",[]}, + {"E","2.0.0",[]}]}, + {"B", "1.0.0", [{"F","1.0.0",[]}, {"G",[]}]}, - {"C", "1", [{"H","4",[]}, + {"C", "1.0.0", [{"H","4.0.0",[]}, {"I",[]}]}], ["A","C","E","H"], - {"C", [{"A","1"}, "D", {"E","3"}, - {"B","1"}, {"F","1"}, "G", - {"C","1"}, {"H","4"}, "I"]}}; + {"C", [{"A","1.0.0"}, "D", {"E","3.0.0"}, + {"B","1.0.0"}, {"F","1.0.0"}, "G", + {"C","1.0.0"}, {"H","4.0.0"}, "I"]}}; upgrades(tree_a) -> - {[{"A", "1", [{"D",[{"J",[]}]}, - {"E",[{"I","1",[]}]}]}, - {"B", "1", [{"F",[]}, + {[{"A", "1.0.0", [{"D",[{"J",[]}]}, + {"E",[{"I","1.0.0",[]}]}]}, + {"B", "1.0.0", [{"F",[]}, {"G",[]}]}, - {"C", "1", [{"H",[]}, - {"I","2",[]}]} + {"C", "1.0.0", [{"H",[]}, + {"I","2.0.0",[]}]} ], - [{"A", "1", [{"D",[{"J",[]}]}, - {"E",[{"I","1",[]}]}]}, - {"B", "1", [{"F",[]}, + [{"A", "1.0.0", [{"D",[{"J",[]}]}, + {"E",[{"I","1.0.0",[]}]}]}, + {"B", "1.0.0", [{"F",[]}, {"G",[]}]}, - {"C", "2", [{"H",[]}]} + {"C", "2.0.0", [{"H",[]}]} ], ["C"], - {"A", [{"A","1"}, "D", "J", "E", - {"B","1"}, "F", "G", - {"C","1"}, "H", {"I","2"}]}}; + {"A", [{"A","1.0.0"}, "D", "J", "E", + {"B","1.0.0"}, "F", "G", + {"C","1.0.0"}, "H", {"I","2.0.0"}]}}; upgrades(tree_b) -> - {[{"A", "1", [{"D",[{"J",[]}]}, - {"E",[{"I","1",[]}]}]}, - {"B", "1", [{"F",[]}, + {[{"A", "1.0.0", [{"D",[{"J",[]}]}, + {"E",[{"I","1.0.0",[]}]}]}, + {"B", "1.0.0", [{"F",[]}, {"G",[]}]}, - {"C", "1", [{"H",[]}, - {"I","2",[]}]} + {"C", "1.0.0", [{"H",[]}, + {"I","2.0.0",[]}]} ], - [{"A", "1", [{"D",[{"J",[]}]}, - {"E",[{"I","1",[]}]}]}, - {"B", "1", [{"F",[]}, + [{"A", "1.0.0", [{"D",[{"J",[]}]}, + {"E",[{"I","1.0.0",[]}]}]}, + {"B", "1.0.0", [{"F",[]}, {"G",[]}]}, - {"C", "2", [{"H",[]}]} + {"C", "2.0.0", [{"H",[]}]} ], ["C"], - {"B", [{"A","1"}, "D", "J", "E", - {"B","1"}, "F", "G", - {"C","1"}, "H", {"I","2"}]}}; + {"B", [{"A","1.0.0"}, "D", "J", "E", + {"B","1.0.0"}, "F", "G", + {"C","1.0.0"}, "H", {"I","2.0.0"}]}}; upgrades(tree_c) -> - {[{"A", "1", [{"D",[{"J",[]}]}, - {"E",[{"I","1",[]}]}]}, - {"B", "1", [{"F",[]}, + {[{"A", "1.0.0", [{"D",[{"J",[]}]}, + {"E",[{"I","1.0.0",[]}]}]}, + {"B", "1.0.0", [{"F",[]}, {"G",[]}]}, - {"C", "1", [{"H",[]}, - {"I","2",[]}]} + {"C", "1.0.0", [{"H",[]}, + {"I","2.0.0",[]}]} ], - [{"A", "1", [{"D",[{"J",[]}]}, - {"E",[{"I","1",[]}]}]}, - {"B", "1", [{"F",[]}, + [{"A", "1.0.0", [{"D",[{"J",[]}]}, + {"E",[{"I","1.0.0",[]}]}]}, + {"B", "1.0.0", [{"F",[]}, {"G",[]}]}, - {"C", "1", [{"H",[]}]} + {"C", "1.0.0", [{"H",[]}]} ], ["C","I"], - {"C", [{"A","1"}, "D", "J", "E", {"I","1"}, - {"B","1"}, "F", "G", - {"C","1"}, "H"]}}; + {"C", [{"A","1.0.0"}, "D", "J", "E", {"I","1.0.0"}, + {"B","1.0.0"}, "F", "G", + {"C","1.0.0"}, "H"]}}; upgrades(tree_c2) -> - {[{"A", "1", [{"D",[{"J",[]}]}, - {"E",[{"I","1",[]}]}]}, - {"B", "1", [{"F",[]}, + {[{"A", "1.0.0", [{"D",[{"J",[]}]}, + {"E",[{"I","1.0.0",[]}]}]}, + {"B", "1.0.0", [{"F",[]}, {"G",[]}]}, - {"C", "1", [{"H",[]}, - {"I","2",[]}]} + {"C", "1.0.0", [{"H",[]}, + {"I","2.0.0",[]}]} ], - [{"A", "1", [{"D",[{"J",[]}]}, - {"E",[{"I","1",[]}]}]}, - {"B", "1", [{"F",[]}, + [{"A", "1.0.0", [{"D",[{"J",[]}]}, + {"E",[{"I","1.0.0",[]}]}]}, + {"B", "1.0.0", [{"F",[]}, {"G",[]}]}, - {"C", "1", [{"H",[{"K",[]}]}, - {"I","2",[]}]} + {"C", "1.0.0", [{"H",[{"K",[]}]}, + {"I","2.0.0",[]}]} ], ["C", "H"], - {"C", [{"A","1"}, "D", "J", "E", - {"B","1"}, "F", "G", - {"C","1"}, "H", {"I", "2"}, "K"]}}; + {"C", [{"A","1.0.0"}, "D", "J", "E", + {"B","1.0.0"}, "F", "G", + {"C","1.0.0"}, "H", {"I", "2.0.0"}, "K"]}}; upgrades(tree_cj) -> - {[{"A", "1", [{"D",[{"J", "1",[]}]}, - {"E",[{"I","1",[]}]}]}, - {"B", "1", [{"F",[]}, + {[{"A", "1.0.0", [{"D",[{"J", "1.0.0",[]}]}, + {"E",[{"I","1.0.0",[]}]}]}, + {"B", "1.0.0", [{"F",[]}, {"G",[]}]}, - {"C", "1", [{"H",[]}, - {"I","1",[]}]} + {"C", "1.0.0", [{"H",[]}, + {"I","1.0.0",[]}]} ], - [{"A", "1", [{"D",[{"J", "2", []}]}, - {"E",[{"I","1",[]}]}]}, - {"B", "1", [{"F",[]}, + [{"A", "1.0.0", [{"D",[{"J", "2.0.0", []}]}, + {"E",[{"I","1.0.0",[]}]}]}, + {"B", "1.0.0", [{"F",[]}, {"G",[]}]}, - {"C", "1", [{"H",[]}, - {"I","1",[]}]} + {"C", "1.0.0", [{"H",[]}, + {"I","1.0.0",[]}]} ], ["C","J"], - {"C", [{"A","1"}, "D", {"J", "1"}, "E", {"I","1"}, - {"B","1"}, "F", "G", - {"C","1"}, "H"]}}; + {"C", [{"A","1.0.0"}, "D", {"J", "1.0.0"}, "E", {"I","1.0.0"}, + {"B","1.0.0"}, "F", "G", + {"C","1.0.0"}, "H"]}}; upgrades(tree_ac) -> - {[{"A", "1", [{"D",[{"J",[]}]}, - {"E",[{"I","1",[]}]}]}, - {"B", "1", [{"F",[]}, + {[{"A", "1.0.0", [{"D",[{"J",[]}]}, + {"E",[{"I","1.0.0",[]}]}]}, + {"B", "1.0.0", [{"F",[]}, {"G",[]}]}, - {"C", "1", [{"H",[]}, - {"I","2",[]}]} + {"C", "1.0.0", [{"H",[]}, + {"I","2.0.0",[]}]} ], - [{"A", "1", [{"D",[{"J",[]}]}, - {"E",[{"I","1",[]}]}]}, - {"B", "1", [{"F",[]}, + [{"A", "1.0.0", [{"D",[{"J",[]}]}, + {"E",[{"I","1.0.0",[]}]}]}, + {"B", "1.0.0", [{"F",[]}, {"G",[]}]}, - {"C", "1", [{"H",[]}]} + {"C", "1.0.0", [{"H",[]}]} ], ["C","I"], - {"C, A", [{"A","1"}, "D", "J", "E", {"I","1"}, - {"B","1"}, "F", "G", - {"C","1"}, "H"]}}; + {"C, A", [{"A","1.0.0"}, "D", "J", "E", {"I","1.0.0"}, + {"B","1.0.0"}, "F", "G", + {"C","1.0.0"}, "H"]}}; upgrades(tree_all) -> - {[{"A", "1", [{"D",[{"J",[]}]}, - {"E",[{"I","1",[]}]}]}, - {"B", "1", [{"F",[]}, + {[{"A", "1.0.0", [{"D",[{"J",[]}]}, + {"E",[{"I","1.0.0",[]}]}]}, + {"B", "1.0.0", [{"F",[]}, {"G",[]}]}, - {"C", "1", [{"H",[]}, - {"I","2",[]}]} + {"C", "1.0.0", [{"H",[]}, + {"I","2.0.0",[]}]} ], - [{"A", "1", [{"D",[{"J",[]}]}, - {"E",[{"I","1",[]}]}]}, - {"B", "1", [{"F",[]}, + [{"A", "1.0.0", [{"D",[{"J",[]}]}, + {"E",[{"I","1.0.0",[]}]}]}, + {"B", "1.0.0", [{"F",[]}, {"G",[]}]}, - {"C", "1", [{"H",[]}]} + {"C", "1.0.0", [{"H",[]}]} ], ["C","I"], - {"", [{"A","1"}, "D", "J", "E", {"I","1"}, - {"B","1"}, "F", "G", - {"C","1"}, "H"]}}; + {"", [{"A","1.0.0"}, "D", "J", "E", {"I","1.0.0"}, + {"B","1.0.0"}, "F", "G", + {"C","1.0.0"}, "H"]}}; upgrades(delete_d) -> - {[{"A", "1", [{"B", [{"D", "1", []}]}, - {"C", [{"D", "2", []}]}]} + {[{"A", "1.0.0", [{"B", [{"D", "1.0.0", []}]}, + {"C", [{"D", "2.0.0", []}]}]} ], - [{"A", "2", [{"B", []}, + [{"A", "2.0.0", [{"B", []}, {"C", []}]} ], ["A","B", "C"], %% upgrade vs. new tree - {"", [{"A","2"}, "B", "C"]}}; + {"", [{"A","2.0.0"}, "B", "C"]}}; upgrades(promote) -> - {[{"A", "1", [{"C", "1", []}]}, - {"B", "1", [{"D", "1", []}]} + {[{"A", "1.0.0", [{"C", "1.0.0", []}]}, + {"B", "1.0.0", [{"D", "1.0.0", []}]} ], - [{"A", "2", [{"C", "2", []}]}, - {"B", "2", [{"D", "2", []}]}, - {"C", "3", []} + [{"A", "2.0.0", [{"C", "2.0.0", []}]}, + {"B", "2.0.0", [{"D", "2.0.0", []}]}, + {"C", "3.0.0", []} ], ["A","B","C","D"], - {"C", [{"A","1"},{"C","3"},{"B","1"},{"D","1"}]}}; + {"C", [{"A","1.0.0"},{"C","3.0.0"},{"B","1.0.0"},{"D","1.0.0"}]}}; upgrades(stable_lock) -> - {[{"A", "1", [{"C", "1", []}]}, - {"B", "1", [{"D", "1", []}]} + {[{"A", "1.0.0", [{"C", "1.0.0", []}]}, + {"B", "1.0.0", [{"D", "1.0.0", []}]} ], % lock after this - [{"A", "2", [{"C", "2", []}]}, - {"B", "2", [{"D", "2", []}]} + [{"A", "2.0.0", [{"C", "2.0.0", []}]}, + {"B", "2.0.0", [{"D", "2.0.0", []}]} ], [], %% Run a regular lock and no app should be upgraded - {"any", [{"A","1"},{"C","1"},{"B","1"},{"D","1"}]}}; + {"any", [{"A","1.0.0"},{"C","1.0.0"},{"B","1.0.0"},{"D","1.0.0"}]}}; upgrades(fwd_lock) -> - {[{"A", "1", [{"C", "1", []}]}, - {"B", "1", [{"D", "1", []}]} + {[{"A", "1.0.0", [{"C", "1.0.0", []}]}, + {"B", "1.0.0", [{"D", "1.0.0", []}]} ], - [{"A", "2", [{"C", "2", []}]}, - {"B", "2", [{"D", "2", []}]} + [{"A", "2.0.0", [{"C", "2.0.0", []}]}, + {"B", "2.0.0", [{"D", "2.0.0", []}]} ], ["A","B","C","D"], %% For this one, we should build, rewrite the lock %% file to include the result post-upgrade, and then %% run a regular lock to see that the lock file is respected %% in deps. - {"any", [{"A","2"},{"C","2"},{"B","2"},{"D","2"}]}}; + {"any", [{"A","2.0.0"},{"C","2.0.0"},{"B","2.0.0"},{"D","2.0.0"}]}}; upgrades(compile_upgrade_parity) -> - {[{"A", "1", [{"D",[{"J",[]}]}, - {"E",[{"I","1",[]}]}]}, - {"B", "1", [{"F",[]}, + {[{"A", "1.0.0", [{"D",[{"J",[]}]}, + {"E",[{"I","1.0.0",[]}]}]}, + {"B", "1.0.0", [{"F",[]}, {"G",[]}]}, - {"C", "1", [{"H",[]}, - {"I","2",[]}]} + {"C", "1.0.0", [{"H",[]}, + {"I","2.0.0",[]}]} ], [], [], - {"", [{"A","1"}, "D", "J", "E", {"I","1"}, - {"B","1"}, "F", "G", - {"C","1"}, "H"]}}; + {"", [{"A","1.0.0"}, "D", "J", "E", {"I","1.0.0"}, + {"B","1.0.0"}, "F", "G", + {"C","1.0.0"}, "H"]}}; upgrades(umbrella_config) -> - {[{"A", "1", []}], - [{"A", "2", []}], + {[{"A", "1.0.0", []}], + [{"A", "2.0.0", []}], ["A"], - {"A", [{"A","2"}]}}; + {"A", [{"A","2.0.0"}]}}; upgrades(profiles) -> %% Ensure that we can unlock deps under a given profile; %% B and C should both be in a custom profile %% and must not be locked. - {[{"A", "1", [{"D",[]}, - {"E","3",[]}]}, - {"B", "1", [{"F","1",[]}, + {[{"A", "1.0.0", [{"D",[]}, + {"E","3.0.0",[]}]}, + {"B", "1.0.0", [{"F","1.0.0",[]}, {"G",[]}]}, - {"C", "0", [{"H","3",[]}, + {"C", "0.0.0", [{"H","3.0.0",[]}, {"I",[]}]}], - [{"A", "2", [{"D",[]}, - {"E","2",[]}]}, - {"B", "2", [{"F","2",[]}, + [{"A", "2.0.0", [{"D",[]}, + {"E","2.0.0",[]}]}, + {"B", "2.0.0", [{"F","2.0.0",[]}, {"G",[]}]}, - {"C", "1", [{"H","4",[]}, + {"C", "1.0.0", [{"H","4.0.0",[]}, {"I",[]}]}], ["A","B","C","E","F","H"], - {"C", [{"A","1"}, "D", {"E","3"}, - {"B","2"}, {"F","2"}, "G", - {"C","1"}, {"H","4"}, "I"]}}; + {"C", [{"A","1.0.0"}, "D", {"E","3.0.0"}, + {"B","2.0.0"}, {"F","2.0.0"}, "G", + {"C","1.0.0"}, {"H","4.0.0"}, "I"]}}; upgrades(profiles_exclusion) -> %% Ensure that we can unlock deps under a given profile; %% B and C should both be in a custom profile %% and must not be locked. - {[{"A", "1", [{"D",[]}, - {"E","3",[]}]}, - {"B", "1", [{"F","1",[]}, + {[{"A", "1.0.0", [{"D",[]}, + {"E","3.0.0",[]}]}, + {"B", "1.0.0", [{"F","1.0.0",[]}, {"G",[]}]}, - {"C", "0", [{"H","3",[]}, + {"C", "0.0.0", [{"H","3.0.0",[]}, {"I",[]}]}], - [{"A", "2", [{"D",[]}, - {"E","2",[]}]}, - {"B", "2", [{"F","2",[]}, + [{"A", "2.0.0", [{"D",[]}, + {"E","2.0.0",[]}]}, + {"B", "2.0.0", [{"F","2.0.0",[]}, {"G",[]}]}, - {"C", "1", [{"H","4",[]}, + {"C", "1.0.0", [{"H","4.0.0",[]}, {"I",[]}]}], ["A","B","C","E","F","H"], - {"A", [{"A","1"}, "D", {"E","3"}, - {"B","2"}, {"F","2"}, "G", - {"C","1"}, {"H","4"}, "I"]}}. + {"A", [{"A","1.0.0"}, "D", {"E","3.0.0"}, + {"B","2.0.0"}, {"F","2.0.0"}, "G", + {"C","1.0.0"}, {"H","4.0.0"}, "I"]}}. %% TODO: add a test that verifies that unlocking files and then %% running the upgrade code is enough to properly upgrade things. -- cgit v1.1