defmodule GitGud.InvitesTest do
use GitGud.DataCase, async: false
alias GitGud.Accounts
alias GitGud.Accounts.Invite
import GitGud.AccountsFixtures
describe "registration_mode/0" do
setup do
original = Application.get_env(:git_gud, :registration_mode, :open)
on_exit(fn -> Application.put_env(:git_gud, :registration_mode, original) end)
:ok
end
test "defaults to :invite_only when the env is missing" do
Application.delete_env(:git_gud, :registration_mode)
assert Accounts.registration_mode() == :invite_only
end
test "accepts atom modes" do
Application.put_env(:git_gud, :registration_mode, :invite_only)
assert Accounts.registration_mode() == :invite_only
Application.put_env(:git_gud, :registration_mode, :closed)
assert Accounts.registration_mode() == :closed
end
test "accepts stringy modes for env-var-driven config" do
Application.put_env(:git_gud, :registration_mode, "invite_only")
assert Accounts.registration_mode() == :invite_only
Application.put_env(:git_gud, :registration_mode, "closed")
assert Accounts.registration_mode() == :closed
end
test "garbage modes fall back to :invite_only" do
Application.put_env(:git_gud, :registration_mode, :nonsense)
assert Accounts.registration_mode() == :invite_only
Application.put_env(:git_gud, :registration_mode, "nope")
assert Accounts.registration_mode() == :invite_only
end
end
describe "register_user/1 mode enforcement" do
setup do
original = Application.get_env(:git_gud, :registration_mode, :open)
on_exit(fn -> Application.put_env(:git_gud, :registration_mode, original) end)
:ok
end
test "refuses when registration is :closed" do
Application.put_env(:git_gud, :registration_mode, :closed)
assert {:error, :registration_closed} = Accounts.register_user(%{email: "x@example"})
end
test "succeeds when :open" do
Application.put_env(:git_gud, :registration_mode, :open)
assert {:ok, %{email: "y@example"}} = Accounts.register_user(%{email: "y@example"})
end
end
describe "create_invite/2 + lifecycle" do
test "issues a unique token" do
user = user_fixture()
{:ok, a} = Accounts.create_invite(user)
{:ok, b} = Accounts.create_invite(user)
assert a.token != b.token
assert a.created_by_id == user.id
assert is_nil(a.consumed_at)
end
test "list_invites returns owner's invites newest first" do
user = user_fixture()
{:ok, _a} = Accounts.create_invite(user)
Process.sleep(1100)
{:ok, b} = Accounts.create_invite(user)
[first, _] = Accounts.list_invites(user)
assert first.id == b.id
end
test "get_active_invite returns active, nil for missing / consumed / expired" do
user = user_fixture()
{:ok, invite} = Accounts.create_invite(user)
assert %Invite{} = Accounts.get_active_invite(invite.token)
refute Accounts.get_active_invite("nope")
refute Accounts.get_active_invite(nil)
newcomer = user_fixture()
{:ok, _} = Accounts.consume_invite(invite, newcomer)
refute Accounts.get_active_invite(invite.token)
end
test "consume stamps consumed_at + consumed_by_id; idempotent" do
user = user_fixture()
newcomer = user_fixture()
{:ok, invite} = Accounts.create_invite(user)
{:ok, c1} = Accounts.consume_invite(invite, newcomer)
assert c1.consumed_at
assert c1.consumed_by_id == newcomer.id
{:ok, c2} = Accounts.consume_invite(c1, newcomer)
assert c2.consumed_at == c1.consumed_at
end
test "revoke only by owner" do
owner = user_fixture()
bystander = user_fixture()
{:ok, invite} = Accounts.create_invite(owner)
assert {:error, :forbidden} = Accounts.revoke_invite(bystander, invite)
{:ok, revoked} = Accounts.revoke_invite(owner, invite)
assert revoked.consumed_at
refute revoked.consumed_by_id
end
test "Invite.active? — true only when not consumed and not expired" do
assert Invite.active?(%Invite{consumed_at: nil, expires_at: nil})
assert Invite.active?(%Invite{
consumed_at: nil,
expires_at: DateTime.add(DateTime.utc_now(), 3600)
})
refute Invite.active?(%Invite{
consumed_at: nil,
expires_at: DateTime.add(DateTime.utc_now(), -1)
})
refute Invite.active?(%Invite{
consumed_at: DateTime.utc_now() |> DateTime.truncate(:second),
expires_at: nil
})
end
end
end
4.6 KiB · text
5af55d9