- %% 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_read_write_read, auth_remove_from_config, auth_merging, auth_config_errors, organization_merging,
- {group, resolve_version}].
-
- groups() ->
- [{resolve_version, [use_first_repo_match, use_exact_with_hash, fail_repo_update,
- ignore_match_in_excluded_repo, optional_prereleases]}].
-
- 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", <<"inner checksum">>, <<"good outer checksum">>, Repo1, false},
- {"A", "0.1.1", <<"inner checksum">>, <<"good outer checksum">>, Repo2, false},
- {"B", "1.0.0", Repo1, false},
- {"B", "2.0.0", Repo2, false},
- {"B", "1.4.0", Repo3, false},
- {"B", "1.4.3", Hexpm, false},
- {"B", "1.4.6", Hexpm, #{reason => 'RETIRED_INVALID'}},
- {"B", "1.5.0", Hexpm, false},
- {"B", "1.5.6-rc.0", Hexpm, true},
- {"C", "1.3.1", <<"inner checksum">>, <<"bad outer checksum">>, Repo1, false},
- {"C", "1.3.1", <<"inner checksum">>, <<"good outer checksum">>, Repo2, false}],
- [{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(optional_prereleases, Config) ->
- Deps = ?config(deps, Config),
- Repos = ?config(repos, Config),
-
- State = setup_deps_and_repos(Deps, Repos),
-
- meck:new(rebar_packages, [passthrough, no_link]),
-
- 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(Case, Config) when Case =:= auth_merging ;
- Case =:= auth_config_errors ;
- Case =:= auth_remove_from_config ;
- Case =:= auth_read_write_read ->
- 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 =:= auth_config_errors ;
- Case =:= organization_merging ;
- Case =:= auth_remove_from_config ;
- Case =:= auth_read_write_read ->
- 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 ;
- Case =:= optional_prereleases ->
- 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">>,
- repo_name => <<"repo-1">>,
- api_url => <<"repo-1/api">>},
- Repo2 = #{name => <<"repo-2">>,
- repo_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.
-
- auth_config_errors(_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(_) ->
- {error, {3,erl_parse,["syntax error before: ","'=>'"]}}
- end),
-
- ?assertThrow(rebar_abort, rebar_pkg_resource:init(pkg, State)),
- meck:expect(file, consult,
- fun(_) ->
- {error, enoent}
- end),
-
-
- {ok, #resource{state=#{ repos := [
- UpdatedRepo1,
- UpdatedRepo2,
- DefaultRepo
- ]}}} = rebar_pkg_resource:init(pkg, State),
-
- ?assertEqual(undefined, maps:get(write_key, UpdatedRepo1, undefined)),
- ?assertEqual(undefined, maps:get(read_key, UpdatedRepo1, undefined)),
- ?assertEqual(undefined, maps:get(repos_key, UpdatedRepo1, undefined)),
- ?assertEqual(undefined, maps:get(write_key, UpdatedRepo2, undefined)),
- ?assertEqual(undefined, maps:get(repos_key, UpdatedRepo2, undefined)),
- ?assertEqual(undefined, maps:get(read_key, UpdatedRepo2, undefined)),
- ?assertEqual(undefined, maps:get(write_key, DefaultRepo, undefined)),
- ok.
-
- auth_read_write_read(_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">>}}]}
- end),
-
- meck:expect(file, write_file,
- fun(_File, CfgBin, _) ->
- case binary:match(CfgBin, <<"foo">>) of
- nomatch ->
- Err = "expected auth config binary with key <<\"foo\">>",
- meck:exception(error, {expected, Err});
- _ ->
- ok
- end
- end),
-
- rebar_hex_repos:update_auth_config(#{<<"foo">> => <<200>>}, State).
-
- auth_remove_from_config(_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">>}}]}
- end),
-
- meck:expect(file, write_file,
- fun(_File, CfgBin, _) ->
- case binary:match(CfgBin, <<"hexpm:repo-1">>) of
- nomatch ->
- ok;
- _ ->
- Err = "expected auth config binary without key <<\"hexpm:repo-1\">>",
- meck:exception(error, {expected, Err})
- end
- end),
-
- rebar_hex_repos:remove_from_auth_config(<<"hexpm:repo-1">>, State).
-
- 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">>,
- repo_name := <<"repo-1">>,
- api_repository := <<"repo-1">>,
- repo_organization := <<"repo-1">>,
- read_key := <<"read key">>,
- write_key := <<"write key hexpm">>},
- #{name := <<"hexpm:repo-2">>,
- parent := <<"hexpm">>,
- repo_name := <<"repo-2">>,
- api_repository := <<"repo-2">>,
- repo_organization := <<"repo-2">>,
- read_key := <<"read key 2">>,
- repos_key := <<"repos key 2">>,
- write_key := <<"write key 2">>},
- #{name := <<"hexpm">>,
- repo_name := <<"hexpm">>,
- api_repository := undefined,
- repo_organization := undefined,
- 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},
- <<"inner checksum">>,<<"outer checksum">>, false, []},
- #{name := Repo2,
- http_adapter := {r3_hex_http_httpc, #{profile := rebar}}}},
- rebar_packages:resolve_version(<<"B">>, <<"> 1.4.0">>, undefined, undefined,
- ?PACKAGE_TABLE, State)),
-
- ?assertMatch({ok,{package,{<<"B">>, {{1,4,0}, {[],[]}}, Repo3},
- <<"inner checksum">>,<<"outer checksum">>, false, []},
- #{name := Repo3,
- http_adapter := {r3_hex_http_httpc, #{profile := rebar}}}},
- rebar_packages:resolve_version(<<"B">>, <<"~> 1.4.0">>, undefined, 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},
- <<"inner checksum">>, <<"good outer checksum">>, false, []},
- #{name := Repo2,
- http_adapter := {r3_hex_http_httpc, #{profile := rebar}}}},
- rebar_packages:resolve_version(<<"C">>, <<"1.3.1">>, <<"inner checksum">>, <<"good outer checksum">>,
- ?PACKAGE_TABLE, State)).
-
- fail_repo_update(Config) ->
- State = ?config(state, Config),
-
- ?assertMatch({ok,{package,{<<"B">>, {{1,4,0}, {[],[]}}, Repo3},
- <<"inner checksum">>,<<"outer checksum">>, false, []},
- #{name := Repo3,
- http_adapter := {r3_hex_http_httpc, #{profile := rebar}}}},
- rebar_packages:resolve_version(<<"B">>, <<"~> 1.4.0">>, undefined, undefined,
- ?PACKAGE_TABLE, State)).
-
- ignore_match_in_excluded_repo(Config) ->
- State = ?config(state, Config),
- Repos = ?config(repos, Config),
-
- ?assertMatch({ok,{package,{<<"B">>, {{1,4,6}, {[],[]}}, Hexpm},
- <<"inner checksum">>,<<"outer checksum">>, #{reason := 'RETIRED_INVALID'}, []},
- #{name := Hexpm,
- http_adapter := {r3_hex_http_httpc, #{profile := rebar}}}},
- rebar_packages:resolve_version(<<"B">>, <<"~> 1.4.0">>, undefined, undefined,
- ?PACKAGE_TABLE, State)),
-
- [_, Repo2 | _] = Repos,
- ?assertMatch({ok,{package,{<<"A">>, {{0,1,1}, {[],[]}}, Repo2},
- <<"inner checksum">>, <<"good outer checksum">>, false, []},
- #{name := Repo2,
- http_adapter := {r3_hex_http_httpc, #{profile := rebar}}}},
- rebar_packages:resolve_version(<<"A">>, <<"0.1.1">>, <<"inner checksum">>, <<"good outer checksum">>,
- ?PACKAGE_TABLE, State)).
-
- optional_prereleases(Config) ->
- State = ?config(state, Config),
-
- ?assertMatch({ok,{package,{<<"B">>, {{1,5,0}, {[],[]}}, Hexpm},
- <<"inner checksum">>,<<"outer checksum">>, false, []},
- #{name := Hexpm,
- http_adapter := {r3_hex_http_httpc, #{profile := rebar}}}},
- rebar_packages:resolve_version(<<"B">>, <<"~> 1.5.0">>, undefined, undefined,
- ?PACKAGE_TABLE, State)),
-
- ?assertMatch({ok,{package,{<<"B">>, {{1,5,6}, {[<<"rc">>,0],[]}}, Hexpm},
- <<"inner checksum">>,<<"outer checksum">>, true, []},
- #{name := Hexpm,
- http_adapter := {r3_hex_http_httpc, #{profile := rebar}}}},
- rebar_packages:resolve_version(<<"B">>, <<"1.5.6-rc.0">>, <<"inner checksum">>, <<"outer checksum">>,
- ?PACKAGE_TABLE, State)),
-
- %% allow prerelease through configuration
- State1 = rebar_state:set(State, deps_allow_prerelease, true),
- ?assertMatch({ok,{package,{<<"B">>, {{1,5,6}, {[<<"rc">>,0],[]}}, Hexpm},
- <<"inner checksum">>,<<"outer checksum">>, true, []},
- #{name := Hexpm,
- http_adapter := {r3_hex_http_httpc, #{profile := rebar}}}},
- rebar_packages:resolve_version(<<"B">>, <<"~> 1.5.0">>, <<"inner checksum">>, <<"outer checksum">>,
- ?PACKAGE_TABLE, State1)).
-
- %%
-
- setup_deps_and_repos(Deps, Repos) ->
- catch ets:delete(?PACKAGE_TABLE),
- 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, Retired}) ->
- ets:insert(?PACKAGE_TABLE, #package{key={rebar_utils:to_binary(Name),
- ec_semver:parse(Version),
- rebar_utils:to_binary(Repo)},
- dependencies=[],
- retired=Retired,
- inner_checksum = <<"inner checksum">>,
- outer_checksum = <<"outer checksum">>});
- ({Name, Version, InnerChecksum, OuterChecksum, Repo, Retired}) ->
- ets:insert(?PACKAGE_TABLE, #package{key={rebar_utils:to_binary(Name),
- ec_semver:parse(Version),
- rebar_utils:to_binary(Repo)},
- dependencies=[],
- retired=Retired,
- inner_checksum = InnerChecksum,
- outer_checksum = OuterChecksum})
- end, Deps).
|