Add NOT NULL constraint to users.role_id and optimize default_role_id
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
- Add database-level NOT NULL constraint for users.role_id - Update SystemActor tests to verify NOT NULL constraint enforcement - Add process dictionary caching for default_role_id/0 to reduce DB queries
This commit is contained in:
parent
86c8b23c77
commit
2d446f63ea
6 changed files with 501 additions and 37 deletions
|
|
@ -4,8 +4,6 @@ defmodule Mv.Helpers.SystemActorTest do
|
|||
"""
|
||||
use Mv.DataCase, async: false
|
||||
|
||||
import Ecto.Query
|
||||
|
||||
alias Mv.Helpers.SystemActor
|
||||
alias Mv.Authorization
|
||||
alias Mv.Accounts
|
||||
|
|
@ -267,18 +265,10 @@ defmodule Mv.Helpers.SystemActorTest do
|
|||
end
|
||||
|
||||
describe "edge cases" do
|
||||
test "raises error if admin user has no role", %{admin_user: admin_user} do
|
||||
# Remove role from admin user by directly setting role_id to NULL in database
|
||||
# (We can't use Ash because allow_nil? false prevents setting role_id to nil)
|
||||
# Convert UUID to binary format for Postgrex
|
||||
admin_user_id = Ecto.UUID.cast!(admin_user.id)
|
||||
|
||||
Mv.Repo.update_all(
|
||||
from(u in "users", where: u.id == type(^admin_user_id, :binary_id)),
|
||||
set: [role_id: nil]
|
||||
)
|
||||
|
||||
# Delete system user to force fallback
|
||||
test "raises error if admin user has invalid role (role loading fails)", %{
|
||||
admin_user: admin_user
|
||||
} do
|
||||
# Delete system user to force fallback to admin user
|
||||
system_actor = SystemActor.get_system_actor()
|
||||
|
||||
case Accounts.User
|
||||
|
|
@ -291,12 +281,29 @@ defmodule Mv.Helpers.SystemActorTest do
|
|||
:ok
|
||||
end
|
||||
|
||||
SystemActor.invalidate_cache()
|
||||
# Test that NOT NULL + FK constraints prevent setting role_id to NULL
|
||||
# We verify this by attempting to set role_id to NULL and expecting a constraint violation
|
||||
admin_user_id = Ecto.UUID.cast!(admin_user.id)
|
||||
admin_user_id_binary = Ecto.UUID.dump!(admin_user_id)
|
||||
|
||||
# Should raise error because admin user has no role
|
||||
assert_raise RuntimeError, ~r/System actor must have a role assigned/, fn ->
|
||||
SystemActor.get_system_actor()
|
||||
end
|
||||
# Attempting to set role_id to NULL should fail due to NOT NULL constraint
|
||||
assert_raise Postgrex.Error,
|
||||
~r/null value in column.*role_id.*violates not-null constraint/i,
|
||||
fn ->
|
||||
Ecto.Adapters.SQL.query!(
|
||||
Mv.Repo,
|
||||
"""
|
||||
UPDATE users
|
||||
SET role_id = NULL
|
||||
WHERE id = $1::uuid
|
||||
""",
|
||||
[admin_user_id_binary]
|
||||
)
|
||||
end
|
||||
|
||||
# Note: With NOT NULL + FK constraints, we can't test the "no role" case directly
|
||||
# because the database prevents it. This is the desired behavior - the constraints
|
||||
# guarantee that role_id is always valid.
|
||||
end
|
||||
|
||||
test "handles concurrent calls without race conditions" do
|
||||
|
|
@ -372,23 +379,32 @@ defmodule Mv.Helpers.SystemActorTest do
|
|||
end
|
||||
end
|
||||
|
||||
test "raises error if system user has no role", %{system_user: system_user} do
|
||||
# Remove role from system user by directly setting role_id to NULL in database
|
||||
# (We can't use Ash because allow_nil? false prevents setting role_id to nil)
|
||||
# Convert UUID to binary format for Postgrex
|
||||
test "raises error if system user has invalid role (role loading fails)", %{
|
||||
system_user: system_user
|
||||
} do
|
||||
# Test that NOT NULL + FK constraints prevent setting role_id to NULL
|
||||
# We verify this by attempting to set role_id to NULL and expecting a constraint violation
|
||||
system_user_id = Ecto.UUID.cast!(system_user.id)
|
||||
system_user_id_binary = Ecto.UUID.dump!(system_user_id)
|
||||
|
||||
Mv.Repo.update_all(
|
||||
from(u in "users", where: u.id == type(^system_user_id, :binary_id)),
|
||||
set: [role_id: nil]
|
||||
)
|
||||
# Attempting to set role_id to NULL should fail due to NOT NULL constraint
|
||||
assert_raise Postgrex.Error,
|
||||
~r/null value in column.*role_id.*violates not-null constraint/i,
|
||||
fn ->
|
||||
Ecto.Adapters.SQL.query!(
|
||||
Mv.Repo,
|
||||
"""
|
||||
UPDATE users
|
||||
SET role_id = NULL
|
||||
WHERE id = $1::uuid
|
||||
""",
|
||||
[system_user_id_binary]
|
||||
)
|
||||
end
|
||||
|
||||
SystemActor.invalidate_cache()
|
||||
|
||||
# Should raise error because system user has no role
|
||||
assert_raise RuntimeError, ~r/System actor must have a role assigned/, fn ->
|
||||
SystemActor.get_system_actor()
|
||||
end
|
||||
# Note: With NOT NULL + FK constraints, we can't test the "no role" case directly
|
||||
# because the database prevents it. This is the desired behavior - the constraints
|
||||
# guarantee that role_id is always valid.
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue