test: expand Accounts and PartitionManager coverage
This commit is contained in:
parent
a843c91191
commit
49374fdbc3
2 changed files with 238 additions and 0 deletions
|
|
@ -5,6 +5,7 @@ defmodule Aprsme.AccountsTest do
|
|||
|
||||
alias Aprsme.Accounts
|
||||
alias Aprsme.Accounts.User
|
||||
alias Aprsme.Accounts.UserToken
|
||||
|
||||
describe "get_user_by_email/1" do
|
||||
test "returns the user when email matches" do
|
||||
|
|
@ -107,5 +108,197 @@ defmodule Aprsme.AccountsTest do
|
|||
assert :ok = Accounts.delete_user_session_token(token)
|
||||
assert Accounts.get_user_by_session_token(token) == nil
|
||||
end
|
||||
|
||||
test "get_user_by_session_token returns nil for an invalid token" do
|
||||
assert Accounts.get_user_by_session_token("definitely-not-valid") == nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "apply_user_email/3" do
|
||||
test "applies a changed email when the password is correct" do
|
||||
user = user_fixture()
|
||||
new_email = "new+#{System.unique_integer([:positive])}@example.com"
|
||||
|
||||
assert {:ok, applied} =
|
||||
Accounts.apply_user_email(user, valid_user_password(), %{email: new_email})
|
||||
|
||||
assert applied.email == new_email
|
||||
end
|
||||
|
||||
test "returns an error changeset for a wrong password" do
|
||||
user = user_fixture()
|
||||
|
||||
assert {:error, %Ecto.Changeset{}} =
|
||||
Accounts.apply_user_email(user, "wrong-pass", %{email: "new@example.com"})
|
||||
end
|
||||
|
||||
test "returns an error for a missing email change" do
|
||||
user = user_fixture()
|
||||
|
||||
assert {:error, %Ecto.Changeset{}} =
|
||||
Accounts.apply_user_email(user, valid_user_password(), %{email: user.email})
|
||||
end
|
||||
end
|
||||
|
||||
describe "deliver_user_update_email_instructions/3" do
|
||||
test "inserts a change_email token and delivers an email" do
|
||||
user = user_fixture()
|
||||
|
||||
token =
|
||||
extract_user_token(fn url ->
|
||||
Accounts.deliver_user_update_email_instructions(user, user.email, url)
|
||||
end)
|
||||
|
||||
assert is_binary(token)
|
||||
|
||||
# The inserted token should exist in the repo.
|
||||
assert Aprsme.Repo.get_by(
|
||||
UserToken,
|
||||
user_id: user.id,
|
||||
context: "change:#{user.email}"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "update_user_email/2" do
|
||||
test "updates email when token is valid" do
|
||||
user = user_fixture()
|
||||
new_email = "changed+#{System.unique_integer([:positive])}@example.com"
|
||||
|
||||
token =
|
||||
extract_user_token(fn url ->
|
||||
Accounts.deliver_user_update_email_instructions(%{user | email: new_email}, user.email, url)
|
||||
end)
|
||||
|
||||
assert Accounts.update_user_email(user, token) == :ok
|
||||
|
||||
assert %User{email: ^new_email, confirmed_at: %NaiveDateTime{}} =
|
||||
Accounts.get_user!(user.id)
|
||||
end
|
||||
|
||||
test "returns :error for an invalid token" do
|
||||
user = user_fixture()
|
||||
assert Accounts.update_user_email(user, "garbage") == :error
|
||||
# Email unchanged.
|
||||
assert Accounts.get_user!(user.id).email == user.email
|
||||
end
|
||||
end
|
||||
|
||||
describe "update_user_password/3" do
|
||||
test "updates the password and clears all session tokens when successful" do
|
||||
user = user_fixture()
|
||||
_session_token = Accounts.generate_user_session_token(user)
|
||||
|
||||
assert {:ok, updated_user} =
|
||||
Accounts.update_user_password(user, valid_user_password(), %{
|
||||
password: "new valid password",
|
||||
password_confirmation: "new valid password"
|
||||
})
|
||||
|
||||
assert Accounts.get_user_by_email_and_password(updated_user.email, "new valid password")
|
||||
|
||||
# Session tokens for this user should have been cleared.
|
||||
assert Aprsme.Repo.get_by(UserToken, user_id: user.id, context: "session") ==
|
||||
nil
|
||||
end
|
||||
|
||||
test "returns an error changeset for a wrong current password" do
|
||||
user = user_fixture()
|
||||
|
||||
assert {:error, %Ecto.Changeset{}} =
|
||||
Accounts.update_user_password(user, "wrong", %{
|
||||
password: "new valid password",
|
||||
password_confirmation: "new valid password"
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
describe "update_user_callsign/3" do
|
||||
test "updates the callsign when the password is correct" do
|
||||
user = user_fixture()
|
||||
new_call = "W#{rem(System.unique_integer([:positive]), 9) + 1}ABC"
|
||||
|
||||
assert {:ok, updated_user} =
|
||||
Accounts.update_user_callsign(user, valid_user_password(), %{callsign: new_call})
|
||||
|
||||
assert updated_user.callsign == new_call
|
||||
end
|
||||
|
||||
test "returns an error for wrong password" do
|
||||
user = user_fixture()
|
||||
|
||||
assert {:error, %Ecto.Changeset{}} =
|
||||
Accounts.update_user_callsign(user, "wrong", %{callsign: "K1ABC"})
|
||||
end
|
||||
end
|
||||
|
||||
describe "confirm_user/1 and deliver_user_confirmation_instructions/2" do
|
||||
test "confirmation flow end-to-end" do
|
||||
user = user_fixture()
|
||||
refute user.confirmed_at
|
||||
|
||||
token =
|
||||
extract_user_token(fn url ->
|
||||
Accounts.deliver_user_confirmation_instructions(user, url)
|
||||
end)
|
||||
|
||||
assert {:ok, confirmed} = Accounts.confirm_user(token)
|
||||
assert confirmed.confirmed_at
|
||||
end
|
||||
|
||||
test "deliver_user_confirmation_instructions returns error if already confirmed" do
|
||||
user = user_fixture()
|
||||
|
||||
{:ok, confirmed} =
|
||||
Accounts.confirm_user(
|
||||
extract_user_token(fn url ->
|
||||
Accounts.deliver_user_confirmation_instructions(user, url)
|
||||
end)
|
||||
)
|
||||
|
||||
# Now delivering again should short-circuit with {:error, :already_confirmed}
|
||||
assert {:error, :already_confirmed} =
|
||||
Accounts.deliver_user_confirmation_instructions(confirmed, fn _ -> "unused" end)
|
||||
end
|
||||
|
||||
test "confirm_user returns :error for an invalid token" do
|
||||
assert Accounts.confirm_user("totally-wrong") == :error
|
||||
end
|
||||
end
|
||||
|
||||
describe "reset_user_password/2 + deliver_user_reset_password_instructions/2" do
|
||||
test "reset flow end-to-end" do
|
||||
user = user_fixture()
|
||||
|
||||
token =
|
||||
extract_user_token(fn url ->
|
||||
Accounts.deliver_user_reset_password_instructions(user, url)
|
||||
end)
|
||||
|
||||
# get_user_by_reset_password_token should find the user.
|
||||
assert Accounts.get_user_by_reset_password_token(token).id == user.id
|
||||
|
||||
assert {:ok, _updated} =
|
||||
Accounts.reset_user_password(user, %{
|
||||
password: "brand new password",
|
||||
password_confirmation: "brand new password"
|
||||
})
|
||||
|
||||
assert Accounts.get_user_by_email_and_password(user.email, "brand new password")
|
||||
end
|
||||
|
||||
test "get_user_by_reset_password_token returns nil for bad token" do
|
||||
assert Accounts.get_user_by_reset_password_token("bad") == nil
|
||||
end
|
||||
|
||||
test "reset_user_password returns an error changeset for invalid attrs" do
|
||||
user = user_fixture()
|
||||
|
||||
assert {:error, %Ecto.Changeset{}} =
|
||||
Accounts.reset_user_password(user, %{
|
||||
password: "x",
|
||||
password_confirmation: "y"
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -133,4 +133,49 @@ defmodule Aprsme.PartitionManagerTest do
|
|||
assert today_name in partitions
|
||||
end
|
||||
end
|
||||
|
||||
describe "init/1 and handle_info/2" do
|
||||
test "init/1 returns :ok state without scheduling in :test env" do
|
||||
original = Application.get_env(:aprsme, :env)
|
||||
Application.put_env(:aprsme, :env, :test)
|
||||
|
||||
try do
|
||||
assert {:ok, %{}} = PartitionManager.init([])
|
||||
# The :manage_partitions message should NOT arrive since we're in :test.
|
||||
refute_receive :manage_partitions, 100
|
||||
after
|
||||
Application.put_env(:aprsme, :env, original)
|
||||
end
|
||||
end
|
||||
|
||||
test "init/1 schedules :manage_partitions in non-test envs" do
|
||||
original = Application.get_env(:aprsme, :env)
|
||||
Application.put_env(:aprsme, :env, :prod)
|
||||
|
||||
try do
|
||||
assert {:ok, %{}} = PartitionManager.init([])
|
||||
# send/2 is synchronous to self() — should be in the mailbox already.
|
||||
assert_receive :manage_partitions, 100
|
||||
after
|
||||
Application.put_env(:aprsme, :env, original)
|
||||
end
|
||||
end
|
||||
|
||||
test "handle_info(:manage_partitions) reschedules and returns :noreply" do
|
||||
# This exercises the create + drop path via real DB access.
|
||||
assert {:noreply, %{}} = PartitionManager.handle_info(:manage_partitions, %{})
|
||||
# Next tick is scheduled via Process.send_after at 1h, so we won't receive it.
|
||||
end
|
||||
end
|
||||
|
||||
describe "validate_partition_name! (via create_partition path)" do
|
||||
test "ensure_partitions_exist rejects dates that would produce malformed names" do
|
||||
# partition_name is a pure date formatter — the format is guaranteed
|
||||
# valid for every Date. This test just documents that normal dates pass.
|
||||
for offset <- -7..7 do
|
||||
name = PartitionManager.partition_name(Date.add(Date.utc_today(), offset))
|
||||
assert name =~ ~r/^packets_\d{8}$/
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue