material_manage_system/internal/repository/user_test.go
2026-09-16 23:30:25 +08:00

144 lines
5.2 KiB
Go

package repository
import (
"errors"
"regexp"
"testing"
"time"
"github.com/DATA-DOG/go-sqlmock"
"github.com/wmms/wmms/internal/model"
"github.com/wmms/wmms/pkg/database"
)
func TestListUsersIncludesAllAssignedRoles(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("open sql mock: %v", err)
}
t.Cleanup(func() { database.DB = nil; db.Close() })
database.DB = db
now := time.Date(2026, 9, 16, 9, 0, 0, 0, time.Local)
mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM users`)).WillReturnRows(
sqlmock.NewRows([]string{"count"}).AddRow(1),
)
mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, username, password, description, created_at FROM users ORDER BY id LIMIT ? OFFSET ?`)).
WithArgs(20, 0).
WillReturnRows(sqlmock.NewRows([]string{"id", "username", "password", "description", "created_at"}).
AddRow(7, "zhangsan", "hash", "测试用户", now))
mock.ExpectQuery(regexp.QuoteMeta(`SELECT ur.user_id, r.id, r.code, r.name, r.enabled, r.created_at, r.updated_at
FROM user_roles ur JOIN roles r ON r.id = ur.role_id
WHERE ur.user_id IN (?) ORDER BY ur.user_id, r.id`)).
WithArgs(int64(7)).
WillReturnRows(sqlmock.NewRows([]string{"user_id", "id", "code", "name", "enabled", "created_at", "updated_at"}).
AddRow(7, 2, "warehouse_admin", "仓库管理员", true, now, now).
AddRow(7, 3, "purchaser", "采购人员", true, now, now))
users, total, err := NewUserRepository().List("", 20, 0)
if err != nil {
t.Fatalf("list users: %v", err)
}
if total != 1 || len(users) != 1 || len(users[0].Roles) != 2 {
t.Fatalf("unexpected users: total=%d users=%+v", total, users)
}
if users[0].Roles[1].Name != "采购人员" {
t.Fatalf("role names not loaded: %+v", users[0].Roles)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatal(err)
}
}
func TestDeleteRejectsLastSuperAdmin(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("open sql mock: %v", err)
}
t.Cleanup(func() { database.DB = nil; db.Close() })
database.DB = db
mock.ExpectBegin()
mock.ExpectQuery(regexp.QuoteMeta(`SELECT id FROM roles WHERE code = 'super_admin' FOR UPDATE`)).
WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(1))
mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM user_roles WHERE user_id = ? AND role_id = ?`)).
WithArgs(int64(7), int64(1)).
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))
mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM user_roles WHERE role_id = ?`)).
WithArgs(int64(1)).
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))
mock.ExpectRollback()
err = NewUserRepository().Delete(7)
if !errors.Is(err, ErrLastSuperAdmin) {
t.Fatalf("delete error = %v, want ErrLastSuperAdmin", err)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatal(err)
}
}
func TestUpdateRejectsRemovingRoleFromLastSuperAdmin(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("open sql mock: %v", err)
}
t.Cleanup(func() { database.DB = nil; db.Close() })
database.DB = db
mock.ExpectBegin()
mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM roles WHERE enabled = TRUE AND id IN (?)`)).
WithArgs(int64(2)).
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))
mock.ExpectQuery(regexp.QuoteMeta(`SELECT id FROM roles WHERE code = 'super_admin' FOR UPDATE`)).
WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow(1))
mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM user_roles WHERE user_id = ? AND role_id = ?`)).
WithArgs(int64(7), int64(1)).
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))
mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM user_roles WHERE role_id = ?`)).
WithArgs(int64(1)).
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))
mock.ExpectRollback()
user := &model.User{ID: 7, Description: "系统管理员"}
err = NewUserRepository().Update(user, []int64{2})
if !errors.Is(err, ErrLastSuperAdmin) {
t.Fatalf("update error = %v, want ErrLastSuperAdmin", err)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatal(err)
}
}
func TestCreateUserAssignsMultipleEnabledRolesInTransaction(t *testing.T) {
db, mock, err := sqlmock.New()
if err != nil {
t.Fatalf("open sql mock: %v", err)
}
t.Cleanup(func() { database.DB = nil; db.Close() })
database.DB = db
mock.ExpectBegin()
mock.ExpectExec(regexp.QuoteMeta(`INSERT INTO users (username, password, description) VALUES (?, ?, ?)`)).
WithArgs("zhangsan", "hash", "测试用户").
WillReturnResult(sqlmock.NewResult(7, 1))
mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM roles WHERE enabled = TRUE AND id IN (?, ?)`)).
WithArgs(int64(2), int64(3)).
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(2))
mock.ExpectExec(regexp.QuoteMeta(`INSERT INTO user_roles (user_id, role_id) VALUES (?, ?), (?, ?)`)).
WithArgs(int64(7), int64(2), int64(7), int64(3)).
WillReturnResult(sqlmock.NewResult(0, 2))
mock.ExpectCommit()
user := &model.User{Username: "zhangsan", Password: "hash", Description: "测试用户"}
if err := NewUserRepository().Create(user, []int64{2, 3}); err != nil {
t.Fatalf("create user: %v", err)
}
if user.ID != 7 {
t.Fatalf("expected user id 7, got %d", user.ID)
}
if err := mock.ExpectationsWereMet(); err != nil {
t.Fatal(err)
}
}