mirror of
https://github.com/xiaoxinpro/nginx-proxy-manager-zh.git
synced 2025-02-02 01:38:15 -05:00
More unit tests and html coverage report
also fixes a limit bug on listquery
This commit is contained in:
parent
e4e70ae6be
commit
9faa36315f
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,6 +8,7 @@ bin/*
|
||||
backend/config.json
|
||||
backend/embed/assets
|
||||
backend/.task
|
||||
backend/coverage.html
|
||||
test/node_modules
|
||||
*/node_modules
|
||||
docs/.vuepress/dist
|
||||
|
@ -49,7 +49,7 @@ func Enforce(permission string) func(http.Handler) http.Handler {
|
||||
}
|
||||
|
||||
userID := uint(claims["uid"].(float64))
|
||||
_, enabled := user.IsEnabled(userID)
|
||||
_, enabled, _ := user.IsEnabled(userID)
|
||||
if token == nil || !enabled {
|
||||
h.ResultErrorJSON(w, r, http.StatusUnauthorized, "Unauthorised", nil)
|
||||
return
|
||||
|
@ -32,7 +32,7 @@ func SSEAuth(next http.Handler) http.Handler {
|
||||
}
|
||||
|
||||
userID := uint(claims["uid"].(float64))
|
||||
_, enabled := user.IsEnabled(userID)
|
||||
_, enabled, _ := user.IsEnabled(userID)
|
||||
if token == nil || !enabled {
|
||||
h.ResultErrorJSON(w, r, http.StatusUnauthorized, "Unauthorised", nil)
|
||||
return
|
||||
|
@ -30,8 +30,10 @@ func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse,
|
||||
}
|
||||
|
||||
// Get rows
|
||||
dbo = entity.AddOffsetLimitToList(dbo, &pageInfo)
|
||||
dbo = entity.AddOrderToList(dbo, pageInfo.Sort, defaultSort)
|
||||
items := make([]Model, 0)
|
||||
if res := entity.AddOrderToList(dbo, &pageInfo, defaultSort).Find(&items); res.Error != nil {
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
|
@ -46,8 +46,10 @@ func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (ent
|
||||
}
|
||||
|
||||
// Get rows
|
||||
dbo = entity.AddOffsetLimitToList(dbo, &pageInfo)
|
||||
dbo = entity.AddOrderToList(dbo, pageInfo.Sort, defaultSort)
|
||||
items := make([]Model, 0)
|
||||
if res := entity.AddOrderToList(dbo, &pageInfo, defaultSort).Find(&items); res.Error != nil {
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
|
@ -30,8 +30,10 @@ func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse,
|
||||
}
|
||||
|
||||
// Get rows
|
||||
dbo = entity.AddOffsetLimitToList(dbo, &pageInfo)
|
||||
dbo = entity.AddOrderToList(dbo, pageInfo.Sort, defaultSort)
|
||||
items := make([]Model, 0)
|
||||
if res := entity.AddOrderToList(dbo, &pageInfo, defaultSort).Find(&items); res.Error != nil {
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
|
@ -30,8 +30,10 @@ func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse,
|
||||
}
|
||||
|
||||
// Get rows
|
||||
dbo = entity.AddOffsetLimitToList(dbo, &pageInfo)
|
||||
dbo = entity.AddOrderToList(dbo, pageInfo.Sort, defaultSort)
|
||||
items := make([]Model, 0)
|
||||
if res := entity.AddOrderToList(dbo, &pageInfo, defaultSort).Find(&items); res.Error != nil {
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
|
@ -32,8 +32,10 @@ func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (ent
|
||||
}
|
||||
|
||||
// Get rows
|
||||
dbo = entity.AddOffsetLimitToList(dbo, &pageInfo)
|
||||
dbo = entity.AddOrderToList(dbo, pageInfo.Sort, defaultSort)
|
||||
items := make([]Model, 0)
|
||||
if res := entity.AddOrderToList(dbo, &pageInfo, defaultSort).Find(&items); res.Error != nil {
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
|
@ -7,11 +7,6 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// ListableModel is a interface for common use
|
||||
type ListableModel interface {
|
||||
TableName() string
|
||||
}
|
||||
|
||||
// ListResponse is the JSON response for users list
|
||||
type ListResponse struct {
|
||||
Total int64 `json:"total"`
|
||||
@ -29,7 +24,6 @@ func ListQueryBuilder(
|
||||
filterMap map[string]model.FilterMapValue,
|
||||
) *gorm.DB {
|
||||
scopes := make([]func(*gorm.DB) *gorm.DB, 0)
|
||||
scopes = append(scopes, ScopeOffsetLimit(pageInfo))
|
||||
scopes = append(scopes, ScopeFilters(filters, filterMap))
|
||||
return database.GetDB().Scopes(scopes...)
|
||||
}
|
||||
@ -38,8 +32,16 @@ func ListQueryBuilder(
|
||||
// Postgres in particular doesn't like count(*) when ordering at the same time
|
||||
func AddOrderToList(
|
||||
dbo *gorm.DB,
|
||||
pageInfo *model.PageInfo,
|
||||
sort []model.Sort,
|
||||
defaultSort model.Sort,
|
||||
) *gorm.DB {
|
||||
return dbo.Scopes(ScopeOrderBy(pageInfo, defaultSort))
|
||||
return dbo.Scopes(ScopeOrderBy(sort, defaultSort))
|
||||
}
|
||||
|
||||
// AddOffsetLimitToList is used after query above is used for pagination
|
||||
func AddOffsetLimitToList(
|
||||
dbo *gorm.DB,
|
||||
pageInfo *model.PageInfo,
|
||||
) *gorm.DB {
|
||||
return dbo.Scopes(ScopeOffsetLimit(pageInfo))
|
||||
}
|
||||
|
@ -30,8 +30,10 @@ func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse,
|
||||
}
|
||||
|
||||
// Get rows
|
||||
dbo = entity.AddOffsetLimitToList(dbo, &pageInfo)
|
||||
dbo = entity.AddOrderToList(dbo, pageInfo.Sort, defaultSort)
|
||||
items := make([]Model, 0)
|
||||
if res := entity.AddOrderToList(dbo, &pageInfo, defaultSort).Find(&items); res.Error != nil {
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
|
@ -19,11 +19,11 @@ func ScopeOffsetLimit(pageInfo *model.PageInfo) func(db *gorm.DB) *gorm.DB {
|
||||
}
|
||||
}
|
||||
|
||||
func ScopeOrderBy(pageInfo *model.PageInfo, defaultSort model.Sort) func(db *gorm.DB) *gorm.DB {
|
||||
func ScopeOrderBy(sort []model.Sort, defaultSort model.Sort) func(db *gorm.DB) *gorm.DB {
|
||||
return func(db *gorm.DB) *gorm.DB {
|
||||
if pageInfo.Sort != nil {
|
||||
if sort != nil {
|
||||
// Sort by items in slice
|
||||
return db.Order(sortToOrderString(pageInfo.Sort))
|
||||
return db.Order(sortToOrderString(sort))
|
||||
} else if defaultSort.Field != "" {
|
||||
// Default to this sort
|
||||
str := defaultSort.Field
|
||||
|
@ -37,8 +37,10 @@ func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse,
|
||||
}
|
||||
|
||||
// Get rows
|
||||
dbo = entity.AddOffsetLimitToList(dbo, &pageInfo)
|
||||
dbo = entity.AddOrderToList(dbo, pageInfo.Sort, defaultSort)
|
||||
items := make([]Model, 0)
|
||||
if res := entity.AddOrderToList(dbo, &pageInfo, defaultSort).Find(&items); res.Error != nil {
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
|
@ -30,8 +30,10 @@ func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse,
|
||||
}
|
||||
|
||||
// Get rows
|
||||
dbo = entity.AddOffsetLimitToList(dbo, &pageInfo)
|
||||
dbo = entity.AddOrderToList(dbo, pageInfo.Sort, defaultSort)
|
||||
items := make([]Model, 0)
|
||||
if res := entity.AddOrderToList(dbo, &pageInfo, defaultSort).Find(&items); res.Error != nil {
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
|
@ -30,8 +30,10 @@ func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (ent
|
||||
}
|
||||
|
||||
// Get rows
|
||||
dbo = entity.AddOffsetLimitToList(dbo, &pageInfo)
|
||||
dbo = entity.AddOrderToList(dbo, pageInfo.Sort, defaultSort)
|
||||
items := make([]Model, 0)
|
||||
if res := entity.AddOrderToList(dbo, &pageInfo, defaultSort).Find(&items); res.Error != nil {
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
|
@ -39,8 +39,10 @@ func List(pageInfo model.PageInfo, filters []model.Filter) (entity.ListResponse,
|
||||
}
|
||||
|
||||
// Get rows
|
||||
dbo = entity.AddOffsetLimitToList(dbo, &pageInfo)
|
||||
dbo = entity.AddOrderToList(dbo, pageInfo.Sort, defaultSort)
|
||||
items := make([]Model, 0)
|
||||
if res := entity.AddOrderToList(dbo, &pageInfo, defaultSort).Find(&items); res.Error != nil {
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
|
421
backend/internal/entity/user/entity_test.go
Normal file
421
backend/internal/entity/user/entity_test.go
Normal file
@ -0,0 +1,421 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
goerrors "errors"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"npm/internal/errors"
|
||||
"npm/internal/model"
|
||||
"npm/internal/test"
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
// +------------+
|
||||
// | Setup |
|
||||
// +------------+
|
||||
|
||||
type testsuite struct {
|
||||
suite.Suite
|
||||
mock sqlmock.Sqlmock
|
||||
singleRow *sqlmock.Rows
|
||||
capabilitiesRows *sqlmock.Rows
|
||||
listCountRows *sqlmock.Rows
|
||||
listRows *sqlmock.Rows
|
||||
}
|
||||
|
||||
// SetupTest is executed before each test
|
||||
func (s *testsuite) SetupTest() {
|
||||
var err error
|
||||
s.mock, err = test.Setup()
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
// These rows need to be intantiated for each test as they are
|
||||
// read in the db object, and their row position is not resettable
|
||||
// between tests.
|
||||
s.singleRow = sqlmock.NewRows([]string{
|
||||
"id",
|
||||
"name",
|
||||
"nickname",
|
||||
"email",
|
||||
"is_disabled",
|
||||
"is_system",
|
||||
}).AddRow(
|
||||
10,
|
||||
"John Doe",
|
||||
"Jonny",
|
||||
"jon@example.com",
|
||||
false,
|
||||
false,
|
||||
)
|
||||
|
||||
s.capabilitiesRows = sqlmock.NewRows([]string{
|
||||
"user_id",
|
||||
"capability_name",
|
||||
}).AddRow(
|
||||
10,
|
||||
"hosts.view",
|
||||
).AddRow(
|
||||
10,
|
||||
"hosts.manage",
|
||||
)
|
||||
|
||||
s.listCountRows = sqlmock.NewRows([]string{
|
||||
"count(*)",
|
||||
}).AddRow(
|
||||
2,
|
||||
)
|
||||
|
||||
s.listRows = sqlmock.NewRows([]string{
|
||||
"id",
|
||||
"name",
|
||||
"nickname",
|
||||
"email",
|
||||
"is_disabled",
|
||||
"is_system",
|
||||
}).AddRow(
|
||||
10,
|
||||
"John Doe",
|
||||
"Jonny",
|
||||
"jon@example.com",
|
||||
false,
|
||||
false,
|
||||
).AddRow(
|
||||
11,
|
||||
"Jane Doe",
|
||||
"Jane",
|
||||
"jane@example.com",
|
||||
true,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
// In order for 'go test' to run this suite, we need to create
|
||||
// a normal test function and pass our suite to suite.Run
|
||||
func TestExampleTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(testsuite))
|
||||
}
|
||||
|
||||
func assertModel(t *testing.T, m Model) {
|
||||
assert.Equal(t, uint(10), m.ID)
|
||||
assert.Equal(t, "John Doe", m.Name)
|
||||
assert.Equal(t, "Jonny", m.Nickname)
|
||||
assert.Equal(t, "jon@example.com", m.Email)
|
||||
assert.Equal(t, false, m.IsDisabled)
|
||||
assert.Equal(t, false, m.IsSystem)
|
||||
}
|
||||
|
||||
// +------------+
|
||||
// | Tests |
|
||||
// +------------+
|
||||
|
||||
func (s *testsuite) TestGetByID() {
|
||||
s.mock.
|
||||
ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "user" WHERE "user"."id" = $1 AND "user"."is_deleted" = $2 ORDER BY "user"."id" LIMIT 1`)).
|
||||
WithArgs(10, 0).
|
||||
WillReturnRows(s.singleRow)
|
||||
|
||||
m, err := GetByID(10)
|
||||
require.NoError(s.T(), err)
|
||||
require.NoError(s.T(), s.mock.ExpectationsWereMet())
|
||||
assertModel(s.T(), m)
|
||||
}
|
||||
|
||||
func (s *testsuite) TestLoadByEmail() {
|
||||
s.mock.
|
||||
ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "user" WHERE email = $1 AND is_system = $2 AND "user"."is_deleted" = $3 ORDER BY "user"."id" LIMIT 1`)).
|
||||
WithArgs("jon@example.com", false, 0).
|
||||
WillReturnRows(s.singleRow)
|
||||
|
||||
m, err := GetByEmail("jon@example.com")
|
||||
require.NoError(s.T(), err)
|
||||
require.NoError(s.T(), s.mock.ExpectationsWereMet())
|
||||
assertModel(s.T(), m)
|
||||
}
|
||||
|
||||
func (s *testsuite) TestIsEnabled() {
|
||||
s.mock.
|
||||
ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "user" WHERE "user"."id" = $1 AND "user"."is_deleted" = $2 ORDER BY "user"."id" LIMIT 1`)).
|
||||
WithArgs(10, 0).
|
||||
WillReturnRows(s.singleRow)
|
||||
|
||||
s.mock.
|
||||
ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "user" WHERE "user"."id" = $1 AND "user"."is_deleted" = $2 ORDER BY "user"."id" LIMIT 1`)).
|
||||
WithArgs(999, 0).
|
||||
WillReturnError(goerrors.New("record not found"))
|
||||
|
||||
// user that exists
|
||||
exists, enabled, err := IsEnabled(10)
|
||||
require.NoError(s.T(), err)
|
||||
assert.Equal(s.T(), true, exists)
|
||||
assert.Equal(s.T(), true, enabled)
|
||||
// that that doesn't exist
|
||||
exists, enabled, err = IsEnabled(999)
|
||||
assert.Equal(s.T(), "record not found", err.Error())
|
||||
assert.Equal(s.T(), false, exists)
|
||||
assert.Equal(s.T(), false, enabled)
|
||||
|
||||
require.NoError(s.T(), s.mock.ExpectationsWereMet())
|
||||
}
|
||||
|
||||
func (s *testsuite) TestSave() {
|
||||
s.mock.
|
||||
ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "user" WHERE email = $1 AND is_system = $2 AND "user"."is_deleted" = $3 ORDER BY "user"."id" LIMIT 1`)).
|
||||
WithArgs("jon@example.com", false, 0).
|
||||
WillReturnRows(s.singleRow)
|
||||
|
||||
s.mock.ExpectBegin()
|
||||
s.mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "user" ("created_at","updated_at","is_deleted","name","nickname","email","is_disabled","is_system") VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING "id"`)).
|
||||
WithArgs(
|
||||
sqlmock.AnyArg(),
|
||||
sqlmock.AnyArg(),
|
||||
0,
|
||||
"John Doe",
|
||||
"Jonny",
|
||||
"sarah@example.com",
|
||||
false,
|
||||
false,
|
||||
).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow("11"))
|
||||
s.mock.ExpectCommit()
|
||||
|
||||
// New model, as system
|
||||
m := Model{
|
||||
Name: "John Doe",
|
||||
Nickname: "Jonny",
|
||||
Email: "JON@example.com", // mixed case on purpose
|
||||
IsSystem: true,
|
||||
}
|
||||
err := m.Save()
|
||||
assert.Equal(s.T(), errors.ErrSystemUserReadonly.Error(), err.Error())
|
||||
|
||||
// Remove system and try again. Expect error due to duplicate email
|
||||
m.IsSystem = false
|
||||
err = m.Save()
|
||||
assert.Equal(s.T(), errors.ErrDuplicateEmailUser.Error(), err.Error())
|
||||
|
||||
// Change email and try again. Expect success
|
||||
m.Email = "sarah@example.com"
|
||||
err = m.Save()
|
||||
require.NoError(s.T(), err)
|
||||
require.NoError(s.T(), s.mock.ExpectationsWereMet())
|
||||
}
|
||||
|
||||
func (s *testsuite) TestDelete() {
|
||||
s.mock.ExpectBegin()
|
||||
s.mock.
|
||||
ExpectExec(regexp.QuoteMeta(`UPDATE "user" SET "is_deleted"=$1 WHERE "user"."id" = $2 AND "user"."is_deleted" = $3`)).
|
||||
WithArgs(1, 10, 0).
|
||||
WillReturnResult(sqlmock.NewResult(0, 1))
|
||||
s.mock.ExpectCommit()
|
||||
|
||||
m := Model{}
|
||||
err := m.Delete()
|
||||
assert.Equal(s.T(), "Unable to delete a new object", err.Error())
|
||||
|
||||
m2 := Model{
|
||||
ModelBase: model.ModelBase{
|
||||
ID: 10,
|
||||
},
|
||||
Name: "John Doe",
|
||||
}
|
||||
err2 := m2.Delete()
|
||||
require.NoError(s.T(), err2)
|
||||
require.NoError(s.T(), s.mock.ExpectationsWereMet())
|
||||
}
|
||||
|
||||
func (s *testsuite) TestGenerateGravatar() {
|
||||
m := Model{Email: "jon@example.com"}
|
||||
m.generateGravatar()
|
||||
assert.Equal(s.T(), "https://www.gravatar.com/avatar/dc36565cc2376197358fa27ed4c47253?d=mm&r=pg&s=128", m.GravatarURL)
|
||||
}
|
||||
|
||||
func (s *testsuite) TestDeleteAll() {
|
||||
s.mock.
|
||||
ExpectExec(regexp.QuoteMeta("DELETE FROM `user` WHERE is_system = $1")).
|
||||
WithArgs(false).
|
||||
WillReturnResult(sqlmock.NewResult(0, 1))
|
||||
|
||||
err := DeleteAll()
|
||||
require.NoError(s.T(), err)
|
||||
require.NoError(s.T(), s.mock.ExpectationsWereMet())
|
||||
}
|
||||
|
||||
func (s *testsuite) TestGetCapabilities() {
|
||||
s.mock.
|
||||
ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "user_has_capability" WHERE user_id = $1`)).
|
||||
WithArgs(10).
|
||||
WillReturnRows(s.capabilitiesRows)
|
||||
|
||||
s.mock.
|
||||
ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "user_has_capability" WHERE user_id = $1`)).
|
||||
WithArgs(999).
|
||||
WillReturnRows(sqlmock.NewRows([]string{}))
|
||||
|
||||
s.mock.
|
||||
ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "user_has_capability" WHERE user_id = $1`)).
|
||||
WithArgs(1000).
|
||||
WillReturnError(goerrors.New("some other error"))
|
||||
|
||||
// user that exists
|
||||
caps, err := GetCapabilities(10)
|
||||
require.NoError(s.T(), err)
|
||||
assert.Equal(s.T(), 2, len(caps))
|
||||
// user that doesn't exist
|
||||
caps, err = GetCapabilities(999)
|
||||
require.NoError(s.T(), err)
|
||||
assert.Equal(s.T(), 0, len(caps))
|
||||
// some other error
|
||||
caps, err = GetCapabilities(1000)
|
||||
assert.Equal(s.T(), "some other error", err.Error())
|
||||
assert.Equal(s.T(), 0, len(caps))
|
||||
|
||||
require.NoError(s.T(), s.mock.ExpectationsWereMet())
|
||||
}
|
||||
|
||||
func (s *testsuite) TestList() {
|
||||
s.mock.
|
||||
ExpectQuery(regexp.QuoteMeta(`SELECT count(*) FROM "user" WHERE name LIKE $1 AND "user"."is_deleted" = $2`)).
|
||||
WithArgs("%jon%", 0).
|
||||
WillReturnRows(s.listCountRows)
|
||||
|
||||
s.mock.
|
||||
ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "user" WHERE name LIKE $1 AND "user"."is_deleted" = $2 ORDER BY name asc LIMIT 8`)).
|
||||
WithArgs("%jon%", 0).
|
||||
WillReturnRows(s.listRows)
|
||||
|
||||
s.mock.
|
||||
ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "user_has_capability" WHERE user_id = $1`)).
|
||||
WithArgs(10).
|
||||
WillReturnRows(s.capabilitiesRows)
|
||||
|
||||
s.mock.
|
||||
ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "user_has_capability" WHERE user_id = $1`)).
|
||||
WithArgs(11).
|
||||
WillReturnRows(sqlmock.NewRows([]string{}))
|
||||
|
||||
p := model.PageInfo{
|
||||
Offset: 0,
|
||||
Limit: 8,
|
||||
Sort: []model.Sort{
|
||||
{
|
||||
Field: "name",
|
||||
Direction: "asc",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
f := []model.Filter{
|
||||
{
|
||||
Field: "name",
|
||||
Modifier: "contains",
|
||||
Value: []string{"jon"},
|
||||
},
|
||||
}
|
||||
|
||||
e := []string{"capabilities"}
|
||||
|
||||
resp, err := List(p, f, e)
|
||||
require.NoError(s.T(), err)
|
||||
assert.Equal(s.T(), int64(2), resp.Total)
|
||||
assert.Equal(s.T(), p.Offset, resp.Offset)
|
||||
assert.Equal(s.T(), p.Limit, resp.Limit)
|
||||
assert.Equal(s.T(), p.Limit, resp.Limit)
|
||||
assert.Equal(s.T(), p.Sort, resp.Sort)
|
||||
assert.Equal(s.T(), f, resp.Filter)
|
||||
|
||||
require.NoError(s.T(), s.mock.ExpectationsWereMet())
|
||||
}
|
||||
|
||||
func (s *testsuite) TestSetPermissions() {
|
||||
s.mock.ExpectBegin()
|
||||
s.mock.
|
||||
ExpectExec(regexp.QuoteMeta(`DELETE FROM "user_has_capability" WHERE user_id = $1`)).
|
||||
WithArgs(10).
|
||||
WillReturnResult(sqlmock.NewResult(0, 1))
|
||||
s.mock.ExpectCommit()
|
||||
|
||||
s.mock.ExpectBegin()
|
||||
s.mock.
|
||||
ExpectExec(regexp.QuoteMeta(`INSERT INTO "user_has_capability" ("user_id","capability_name") VALUES ($1,$2),($3,$4)`)).
|
||||
WithArgs(10, "hosts.view", 10, "hosts.manage").
|
||||
WillReturnResult(sqlmock.NewResult(88, 0))
|
||||
s.mock.ExpectCommit()
|
||||
|
||||
// Empty model returns error
|
||||
m := Model{}
|
||||
err := m.SetPermissions([]string{"hosts.view", "hosts.manage"})
|
||||
assert.Equal(s.T(), "Cannot set permissions without first saving the User", err.Error())
|
||||
|
||||
// Defined user
|
||||
m.ID = 10
|
||||
err = m.SetPermissions([]string{"hosts.view", "hosts.manage"})
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
require.NoError(s.T(), s.mock.ExpectationsWereMet())
|
||||
}
|
||||
|
||||
func (s *testsuite) TestSaveCapabilities() {
|
||||
s.mock.
|
||||
ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "capability"`)).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"name"}).
|
||||
AddRow("full-admin").
|
||||
AddRow("hosts.view").
|
||||
AddRow("hosts.manage"))
|
||||
|
||||
s.mock.ExpectBegin()
|
||||
s.mock.
|
||||
ExpectExec(regexp.QuoteMeta(`DELETE FROM "user_has_capability" WHERE user_id = $1`)).
|
||||
WithArgs(10).
|
||||
WillReturnResult(sqlmock.NewResult(0, 1))
|
||||
s.mock.ExpectCommit()
|
||||
|
||||
s.mock.ExpectBegin()
|
||||
s.mock.
|
||||
ExpectExec(regexp.QuoteMeta(`INSERT INTO "user_has_capability" ("user_id","capability_name") VALUES ($1,$2),($3,$4)`)).
|
||||
WithArgs(10, "hosts.view", 10, "hosts.manage").
|
||||
WillReturnResult(sqlmock.NewResult(88, 0))
|
||||
s.mock.ExpectCommit()
|
||||
|
||||
// Empty model returns error
|
||||
m := Model{}
|
||||
err := m.SaveCapabilities()
|
||||
assert.Equal(s.T(), "Cannot save capabilities on unsaved user", err.Error())
|
||||
|
||||
// Empty model returns error
|
||||
m.ID = 10
|
||||
err = m.SaveCapabilities()
|
||||
assert.Equal(s.T(), "At least 1 capability required for a user", err.Error())
|
||||
|
||||
// With some caps
|
||||
m.Capabilities = []string{"hosts.view", "hosts.manage"}
|
||||
err = m.SaveCapabilities()
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
require.NoError(s.T(), s.mock.ExpectationsWereMet())
|
||||
}
|
||||
|
||||
func (s *testsuite) TestSaveCapabilitiesInvalid() {
|
||||
s.mock.
|
||||
ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "capability"`)).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"name"}).
|
||||
AddRow("full-admin").
|
||||
AddRow("hosts.view").
|
||||
AddRow("hosts.manage"))
|
||||
|
||||
// Empty model returns error
|
||||
m := Model{
|
||||
ModelBase: model.ModelBase{
|
||||
ID: 10,
|
||||
},
|
||||
Capabilities: []string{"doesnotexist", "hosts.manage"},
|
||||
}
|
||||
err := m.SaveCapabilities()
|
||||
assert.Equal(s.T(), "Capability `doesnotexist` is not valid", err.Error())
|
||||
|
||||
require.NoError(s.T(), s.mock.ExpectationsWereMet())
|
||||
}
|
@ -23,14 +23,14 @@ func GetByEmail(email string) (Model, error) {
|
||||
}
|
||||
|
||||
// IsEnabled is used by middleware to ensure the user is still enabled
|
||||
// returns (userExist, isEnabled)
|
||||
func IsEnabled(userID uint) (bool, bool) {
|
||||
// returns (userExist, isEnabled, error)
|
||||
func IsEnabled(userID uint) (bool, bool, error) {
|
||||
var user Model
|
||||
db := database.GetDB()
|
||||
if result := db.First(&user, userID); result.Error != nil {
|
||||
return false, false
|
||||
return false, false, result.Error
|
||||
}
|
||||
return true, !user.IsDisabled
|
||||
return true, !user.IsDisabled, nil
|
||||
}
|
||||
|
||||
// List will return a list of users
|
||||
@ -51,8 +51,10 @@ func List(pageInfo model.PageInfo, filters []model.Filter, expand []string) (ent
|
||||
}
|
||||
|
||||
// Get rows
|
||||
dbo = entity.AddOffsetLimitToList(dbo, &pageInfo)
|
||||
dbo = entity.AddOrderToList(dbo, pageInfo.Sort, defaultSort)
|
||||
items := make([]Model, 0)
|
||||
if res := entity.AddOrderToList(dbo, &pageInfo, defaultSort).Find(&items); res.Error != nil {
|
||||
if res := dbo.Find(&items); res.Error != nil {
|
||||
return result, res.Error
|
||||
}
|
||||
|
||||
|
@ -1,154 +0,0 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"npm/internal/errors"
|
||||
"npm/internal/model"
|
||||
"npm/internal/test"
|
||||
|
||||
"github.com/DATA-DOG/go-sqlmock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
// +------------+
|
||||
// | Setup |
|
||||
// +------------+
|
||||
|
||||
type testsuite struct {
|
||||
suite.Suite
|
||||
mock sqlmock.Sqlmock
|
||||
singleRow *sqlmock.Rows
|
||||
}
|
||||
|
||||
// SetupTest is executed before each test
|
||||
func (s *testsuite) SetupTest() {
|
||||
var err error
|
||||
s.mock, err = test.Setup()
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
s.singleRow = sqlmock.NewRows([]string{
|
||||
"id",
|
||||
"name",
|
||||
"nickname",
|
||||
"email",
|
||||
"is_disabled",
|
||||
"is_system",
|
||||
}).AddRow(
|
||||
10,
|
||||
"John Doe",
|
||||
"Jonny",
|
||||
"jon@example.com",
|
||||
false,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
// In order for 'go test' to run this suite, we need to create
|
||||
// a normal test function and pass our suite to suite.Run
|
||||
func TestExampleTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(testsuite))
|
||||
}
|
||||
|
||||
// +------------+
|
||||
// | Tests |
|
||||
// +------------+
|
||||
|
||||
func (s *testsuite) TestLoadByID() {
|
||||
s.mock.
|
||||
ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "user" WHERE "user"."id" = $1 AND "user"."is_deleted" = $2 ORDER BY "user"."id" LIMIT 1`)).
|
||||
WithArgs(10, 0).
|
||||
WillReturnRows(s.singleRow)
|
||||
|
||||
m := Model{}
|
||||
err := m.LoadByID(10)
|
||||
require.NoError(s.T(), err)
|
||||
require.NoError(s.T(), s.mock.ExpectationsWereMet())
|
||||
}
|
||||
|
||||
func (s *testsuite) TestLoadByEmail() {
|
||||
s.mock.
|
||||
ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "user" WHERE email = $1 AND is_system = $2 AND "user"."is_deleted" = $3 ORDER BY "user"."id" LIMIT 1`)).
|
||||
WithArgs("jon@example.com", false, 0).
|
||||
WillReturnRows(s.singleRow)
|
||||
|
||||
m := Model{}
|
||||
err := m.LoadByEmail("jon@example.com")
|
||||
require.NoError(s.T(), err)
|
||||
require.NoError(s.T(), s.mock.ExpectationsWereMet())
|
||||
}
|
||||
|
||||
func (s *testsuite) TestSave() {
|
||||
s.mock.
|
||||
ExpectQuery(regexp.QuoteMeta(`SELECT * FROM "user" WHERE email = $1 AND is_system = $2 AND "user"."is_deleted" = $3 ORDER BY "user"."id" LIMIT 1`)).
|
||||
WithArgs("jon@example.com", false, 0).
|
||||
WillReturnRows(s.singleRow)
|
||||
|
||||
s.mock.ExpectBegin()
|
||||
s.mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "user" ("created_at","updated_at","is_deleted","name","nickname","email","is_disabled","is_system") VALUES ($1,$2,$3,$4,$5,$6,$7,$8) RETURNING "id"`)).
|
||||
WithArgs(
|
||||
sqlmock.AnyArg(),
|
||||
sqlmock.AnyArg(),
|
||||
0,
|
||||
"John Doe",
|
||||
"Jonny",
|
||||
"sarah@example.com",
|
||||
false,
|
||||
false,
|
||||
).
|
||||
WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow("11"))
|
||||
s.mock.ExpectCommit()
|
||||
|
||||
// New model, as system
|
||||
m := Model{
|
||||
Name: "John Doe",
|
||||
Nickname: "Jonny",
|
||||
Email: "JON@example.com", // mixed case on purpose
|
||||
IsSystem: true,
|
||||
}
|
||||
err := m.Save()
|
||||
assert.Equal(s.T(), errors.ErrSystemUserReadonly.Error(), err.Error())
|
||||
|
||||
// Remove system and try again. Expect error due to duplicate email
|
||||
m.IsSystem = false
|
||||
err = m.Save()
|
||||
assert.Equal(s.T(), errors.ErrDuplicateEmailUser.Error(), err.Error())
|
||||
|
||||
// Change email and try again. Expect success
|
||||
m.Email = "sarah@example.com"
|
||||
err = m.Save()
|
||||
require.NoError(s.T(), err)
|
||||
require.NoError(s.T(), s.mock.ExpectationsWereMet())
|
||||
}
|
||||
|
||||
func (s *testsuite) TestDelete() {
|
||||
s.mock.ExpectBegin()
|
||||
s.mock.
|
||||
ExpectExec(regexp.QuoteMeta(`UPDATE "user" SET "is_deleted"=$1 WHERE "user"."id" = $2 AND "user"."is_deleted" = $3`)).
|
||||
WithArgs(1, 10, 0).
|
||||
WillReturnResult(sqlmock.NewResult(0, 1))
|
||||
s.mock.ExpectCommit()
|
||||
|
||||
m := Model{}
|
||||
err := m.Delete()
|
||||
assert.Equal(s.T(), "Unable to delete a new object", err.Error())
|
||||
|
||||
m2 := Model{
|
||||
ModelBase: model.ModelBase{
|
||||
ID: 10,
|
||||
},
|
||||
Name: "John Doe",
|
||||
}
|
||||
err2 := m2.Delete()
|
||||
require.NoError(s.T(), err2)
|
||||
require.NoError(s.T(), s.mock.ExpectationsWereMet())
|
||||
}
|
||||
|
||||
func (s *testsuite) TestGenerateGravatar() {
|
||||
m := Model{Email: "jon@example.com"}
|
||||
m.generateGravatar()
|
||||
assert.Equal(s.T(), "https://www.gravatar.com/avatar/dc36565cc2376197358fa27ed4c47253?d=mm&r=pg&s=128", m.GravatarURL)
|
||||
}
|
@ -1,3 +1,7 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
go test -json -cover ./internal/... | tparse
|
||||
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
go test -json -cover -coverprofile="$DIR/../coverage.out" ./internal/... | tparse
|
||||
go tool cover -html="$DIR/../coverage.out" -o "$DIR/../coverage.html"
|
||||
rm -f "$DIR/../coverage.out"
|
||||
|
Loading…
Reference in New Issue
Block a user