defmodule GitGud.ModerationTest do
use GitGud.DataCase, async: false
import GitGud.AccountsFixtures
import GitGud.ForgeFixtures
alias GitGud.Issues
alias GitGud.Moderation
alias GitGud.Organizations
alias GitGud.PullRequests
alias GitGud.Repositories
defp org_repo(handle) do
admin = user_fixture()
{:ok, org} = Organizations.create_organization(admin, %{"handle" => handle})
{:ok, repo} =
Repositories.create_repository_for_org(org, admin, %{
"name" => "repo-#{System.unique_integer([:positive])}",
"visibility" => "public"
})
{admin, org, repo}
end
describe "scope" do
test "a repo ban applies to that repo" do
{_owner, repo} = repository_fixture()
nuisance = user_fixture()
{:ok, _ban} = Moderation.ban(repo, nuisance)
assert Moderation.banned?(repo, nuisance)
end
test "a repo ban doesn't leak to another repo" do
{_owner, repo} = repository_fixture()
{_other_owner, other} = repository_fixture()
nuisance = user_fixture()
{:ok, _ban} = Moderation.ban(repo, nuisance)
refute Moderation.banned?(other, nuisance)
end
test "an org ban covers every repo the org owns" do
{_admin, org, repo} = org_repo("mod-org-wide")
nuisance = user_fixture()
{:ok, _ban} = Moderation.ban(org, nuisance)
assert Moderation.banned?(repo, nuisance)
end
test "an org ban covers repos added after it" do
{admin, org, _repo} = org_repo("mod-org-later")
nuisance = user_fixture()
{:ok, _ban} = Moderation.ban(org, nuisance)
{:ok, later} =
Repositories.create_repository_for_org(org, admin, %{
"name" => "added-later",
"visibility" => "public"
})
assert Moderation.banned?(later, nuisance)
end
test "a ban needs exactly one scope" do
user = user_fixture()
assert {:error, cs} =
%GitGud.Moderation.Ban{}
|> GitGud.Moderation.Ban.changeset(%{banned_user_id: user.id})
|> GitGud.Repo.insert()
refute cs.valid?
end
test "anonymous visitors are never banned" do
{_owner, repo} = repository_fixture()
refute Moderation.banned?(repo, nil)
end
end
describe "lifting and expiry" do
test "a lifted ban stops applying" do
{owner, repo} = repository_fixture()
nuisance = user_fixture()
{:ok, ban} = Moderation.ban(repo, nuisance)
{:ok, _} = Moderation.lift(ban, owner)
refute Moderation.banned?(repo, nuisance)
end
test "a lifted ban is kept as a record" do
{owner, repo} = repository_fixture()
nuisance = user_fixture()
{:ok, ban} = Moderation.ban(repo, nuisance, reason: "spam")
{:ok, _} = Moderation.lift(ban, owner)
assert [kept] = Moderation.list_bans(repo)
assert kept.reason == "spam"
assert kept.lifted_at
assert kept.lifted_by_id == owner.id
end
test "an expired ban stops applying without any sweeper" do
{_owner, repo} = repository_fixture()
nuisance = user_fixture()
# Insert directly: the changeset rightly refuses a past expiry.
GitGud.Repo.insert!(%GitGud.Moderation.Ban{
repository_id: repo.id,
banned_user_id: nuisance.id,
expires_at: DateTime.utc_now(:second) |> DateTime.add(-60, :second)
})
refute Moderation.banned?(repo, nuisance)
end
test "a future expiry is still in force" do
{_owner, repo} = repository_fixture()
nuisance = user_fixture()
later = DateTime.utc_now(:second) |> DateTime.add(3600, :second)
{:ok, _ban} = Moderation.ban(repo, nuisance, expires_at: later)
assert Moderation.banned?(repo, nuisance)
end
test "an expiry in the past is refused up front" do
{_owner, repo} = repository_fixture()
nuisance = user_fixture()
past = DateTime.utc_now(:second) |> DateTime.add(-60, :second)
assert {:error, cs} = Moderation.ban(repo, nuisance, expires_at: past)
assert "must be in the future" in errors_on(cs).expires_at
end
test "banning the same person twice in a scope is refused" do
{_owner, repo} = repository_fixture()
nuisance = user_fixture()
{:ok, _} = Moderation.ban(repo, nuisance)
assert {:error, _cs} = Moderation.ban(repo, nuisance)
end
test "they can be re-banned after a lift" do
{owner, repo} = repository_fixture()
nuisance = user_fixture()
{:ok, ban} = Moderation.ban(repo, nuisance)
{:ok, _} = Moderation.lift(ban, owner)
assert {:ok, _} = Moderation.ban(repo, nuisance)
end
test "an org ban outranks a repo one when reporting why" do
{_admin, org, repo} = org_repo("mod-precedence")
nuisance = user_fixture()
{:ok, _repo_ban} = Moderation.ban(repo, nuisance, reason: "repo level")
{:ok, _org_ban} = Moderation.ban(org, nuisance, reason: "org level")
assert Moderation.active_ban(repo, nuisance).reason == "org level"
end
end
describe "enforcement" do
setup do
{owner, repo} = repository_fixture(%{visibility: "public"})
nuisance = user_fixture()
{:ok, _ban} = Moderation.ban(repo, nuisance, reason: "spam")
{:ok, owner: owner, repo: repo, nuisance: nuisance}
end
test "can't open an issue", %{repo: repo, nuisance: nuisance} do
assert {:error, :banned} = Issues.create_issue(repo, nuisance, %{"title" => "hello"})
end
test "can't comment on an issue", %{owner: owner, repo: repo, nuisance: nuisance} do
issue = issue_fixture(repo, owner)
assert {:error, :banned} = Issues.add_comment(issue, nuisance, %{"body" => "spam"})
end
test "can't comment on a PR", %{owner: owner, repo: repo, nuisance: nuisance} do
pr = pr_with_branches(repo, owner)
assert {:error, :banned} = PullRequests.add_comment(pr, nuisance, %{"body" => "spam"})
end
test "can't review a PR", %{owner: owner, repo: repo, nuisance: nuisance} do
pr = pr_with_branches(repo, owner)
assert {:error, :banned} = PullRequests.add_review(pr, nuisance, %{"state" => "approved"})
end
test "can't be asked to review", %{owner: owner, repo: repo, nuisance: nuisance} do
pr = pr_with_branches(repo, owner)
assert {:error, :banned} = PullRequests.request_review(pr, nuisance, owner)
end
test "can't open a PR", %{repo: repo, nuisance: nuisance} do
# Give them something to propose.
seed_main_branch(repo, nuisance)
assert {:error, :banned} =
PullRequests.create_pull_request(repo, nuisance, %{
"title" => "nope",
"source_ref" => "main",
"target_ref" => "main"
})
end
test "everyone else is unaffected", %{owner: owner, repo: repo} do
assert {:ok, _} = Issues.create_issue(repo, owner, %{"title" => "fine"})
end
test "and they can act again once lifted", %{owner: owner, repo: repo, nuisance: nuisance} do
[ban] = Moderation.list_bans(repo)
{:ok, _} = Moderation.lift(ban, owner)
assert {:ok, _} = Issues.create_issue(repo, nuisance, %{"title" => "back"})
end
end
test "banned_user_ids covers both scopes" do
{_admin, org, repo} = org_repo("mod-ids")
org_banned = user_fixture()
repo_banned = user_fixture()
{:ok, _} = Moderation.ban(org, org_banned)
{:ok, _} = Moderation.ban(repo, repo_banned)
ids = Moderation.banned_user_ids(repo)
assert org_banned.id in ids
assert repo_banned.id in ids
end
end
neiam /gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Packages
⭐
Log in to mark this repository.
7.4 KiB · text
History
6280797