feat: 实现企业卡授权和授权记录管理功能
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m9s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m9s
主要功能: - 添加企业卡授权/回收接口 (POST /enterprises/:id/allocate-cards, recall-cards) - 添加授权记录管理接口 (GET/PUT /authorizations) - 实现代理用户数据权限过滤(只能查看自己店铺下企业的授权记录) - 添加 GORM callback 支持授权记录表的数据权限过滤 技术改进: - 原生 SQL 查询手动添加数据权限过滤(ListWithJoin, GetByIDWithJoin) - 移除卡授权预检接口(allocate-cards/preview),保留内部方法 - 完善单元测试和集成测试覆盖
This commit is contained in:
529
tests/integration/authorization_test.go
Normal file
529
tests/integration/authorization_test.go
Normal file
@@ -0,0 +1,529 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/bootstrap"
|
||||
internalMiddleware "github.com/break/junhong_cmp_fiber/internal/middleware"
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/internal/routes"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/auth"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/config"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/queue"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/response"
|
||||
"github.com/break/junhong_cmp_fiber/tests/testutil"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
testDBDSN = "host=cxd.whcxd.cn port=16159 user=erp_pgsql password=erp_2025 dbname=junhong_cmp_test sslmode=disable TimeZone=Asia/Shanghai"
|
||||
testRedisAddr = "cxd.whcxd.cn:16299"
|
||||
testRedisPasswd = "cpNbWtAaqgo1YJmbMp3h"
|
||||
testRedisDB = 6
|
||||
)
|
||||
|
||||
type authorizationTestEnv struct {
|
||||
db *gorm.DB
|
||||
rdb *redis.Client
|
||||
tokenManager *auth.TokenManager
|
||||
app *fiber.App
|
||||
adminToken string
|
||||
agentToken string
|
||||
enterprise *model.Enterprise
|
||||
card1 *model.IotCard
|
||||
card2 *model.IotCard
|
||||
auth1 *model.EnterpriseCardAuthorization
|
||||
shop *model.Shop
|
||||
agentAccount *model.Account
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
func setupTestEnvVars(t *testing.T) {
|
||||
t.Helper()
|
||||
t.Setenv("JUNHONG_DATABASE_HOST", "cxd.whcxd.cn")
|
||||
t.Setenv("JUNHONG_DATABASE_PORT", "16159")
|
||||
t.Setenv("JUNHONG_DATABASE_USER", "erp_pgsql")
|
||||
t.Setenv("JUNHONG_DATABASE_PASSWORD", "erp_2025")
|
||||
t.Setenv("JUNHONG_DATABASE_DBNAME", "junhong_cmp_test")
|
||||
t.Setenv("JUNHONG_DATABASE_SSLMODE", "disable")
|
||||
t.Setenv("JUNHONG_REDIS_ADDRESS", "cxd.whcxd.cn")
|
||||
t.Setenv("JUNHONG_REDIS_PORT", "16299")
|
||||
t.Setenv("JUNHONG_REDIS_PASSWORD", "cpNbWtAaqgo1YJmbMp3h")
|
||||
t.Setenv("JUNHONG_REDIS_DB", "6")
|
||||
t.Setenv("JUNHONG_JWT_SECRET_KEY", "dev-secret-key-for-testing-only-32chars!")
|
||||
t.Setenv("JUNHONG_SERVER_ADDRESS", ":3000")
|
||||
t.Setenv("JUNHONG_LOGGING_LEVEL", "debug")
|
||||
t.Setenv("JUNHONG_LOGGING_DEVELOPMENT", "true")
|
||||
}
|
||||
|
||||
func setupAuthorizationTestEnv(t *testing.T) *authorizationTestEnv {
|
||||
t.Helper()
|
||||
|
||||
setupTestEnvVars(t)
|
||||
cfg, err := config.Load()
|
||||
require.NoError(t, err)
|
||||
err = config.Set(cfg)
|
||||
require.NoError(t, err)
|
||||
|
||||
zapLogger, _ := zap.NewDevelopment()
|
||||
|
||||
db, err := gorm.Open(postgres.Open(testDBDSN), &gorm.Config{
|
||||
Logger: logger.Default.LogMode(logger.Silent),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
rdb := redis.NewClient(&redis.Options{
|
||||
Addr: testRedisAddr,
|
||||
Password: testRedisPasswd,
|
||||
DB: testRedisDB,
|
||||
})
|
||||
|
||||
ctx := context.Background()
|
||||
err = rdb.Ping(ctx).Err()
|
||||
require.NoError(t, err)
|
||||
|
||||
testPrefix := fmt.Sprintf("test:%s:", t.Name())
|
||||
keys, _ := rdb.Keys(ctx, testPrefix+"*").Result()
|
||||
if len(keys) > 0 {
|
||||
rdb.Del(ctx, keys...)
|
||||
}
|
||||
|
||||
tokenManager := auth.NewTokenManager(rdb, 24*time.Hour, 7*24*time.Hour)
|
||||
superAdmin := testutil.CreateSuperAdmin(t, db)
|
||||
adminToken, _ := testutil.GenerateTestToken(t, rdb, superAdmin, "web")
|
||||
|
||||
queueClient := queue.NewClient(rdb, zapLogger)
|
||||
|
||||
deps := &bootstrap.Dependencies{
|
||||
DB: db,
|
||||
Redis: rdb,
|
||||
Logger: zapLogger,
|
||||
TokenManager: tokenManager,
|
||||
QueueClient: queueClient,
|
||||
}
|
||||
|
||||
result, err := bootstrap.Bootstrap(deps)
|
||||
require.NoError(t, err)
|
||||
|
||||
app := fiber.New(fiber.Config{
|
||||
ErrorHandler: internalMiddleware.ErrorHandler(zapLogger),
|
||||
})
|
||||
|
||||
routes.RegisterRoutes(app, result.Handlers, result.Middlewares)
|
||||
|
||||
ts := time.Now().Unix() % 100000
|
||||
shop := &model.Shop{
|
||||
ShopName: "AUTH_TEST_SHOP",
|
||||
ShopCode: fmt.Sprintf("AS%d", ts),
|
||||
Level: 1,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
shop.Creator = superAdmin.ID
|
||||
shop.Updater = superAdmin.ID
|
||||
require.NoError(t, db.Create(shop).Error)
|
||||
|
||||
enterprise := &model.Enterprise{
|
||||
EnterpriseName: "AUTH_TEST_ENTERPRISE",
|
||||
EnterpriseCode: fmt.Sprintf("AE%d", ts),
|
||||
OwnerShopID: &shop.ID,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
enterprise.Creator = superAdmin.ID
|
||||
enterprise.Updater = superAdmin.ID
|
||||
require.NoError(t, db.Create(enterprise).Error)
|
||||
|
||||
card1 := &model.IotCard{
|
||||
ICCID: fmt.Sprintf("AC1%d", ts),
|
||||
MSISDN: "13800001001",
|
||||
CardType: "data_card",
|
||||
Status: 1,
|
||||
ShopID: &shop.ID,
|
||||
}
|
||||
card2 := &model.IotCard{
|
||||
ICCID: fmt.Sprintf("AC2%d", ts),
|
||||
MSISDN: "13800001002",
|
||||
CardType: "data_card",
|
||||
Status: 1,
|
||||
ShopID: &shop.ID,
|
||||
}
|
||||
require.NoError(t, db.Create(card1).Error)
|
||||
require.NoError(t, db.Create(card2).Error)
|
||||
|
||||
now := time.Now()
|
||||
auth1 := &model.EnterpriseCardAuthorization{
|
||||
EnterpriseID: enterprise.ID,
|
||||
CardID: card1.ID,
|
||||
AuthorizedBy: superAdmin.ID,
|
||||
AuthorizedAt: now,
|
||||
AuthorizerType: constants.UserTypePlatform,
|
||||
Remark: "集成测试授权记录",
|
||||
}
|
||||
require.NoError(t, db.Create(auth1).Error)
|
||||
|
||||
agentAccount := &model.Account{
|
||||
Username: fmt.Sprintf("aa%d", ts),
|
||||
Phone: fmt.Sprintf("138%05d", ts),
|
||||
Password: "hashed_password",
|
||||
UserType: constants.UserTypeAgent,
|
||||
ShopID: &shop.ID,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
agentAccount.Creator = superAdmin.ID
|
||||
agentAccount.Updater = superAdmin.ID
|
||||
require.NoError(t, db.Create(agentAccount).Error)
|
||||
|
||||
agentToken, _ := testutil.GenerateTestToken(t, rdb, agentAccount, "web")
|
||||
|
||||
return &authorizationTestEnv{
|
||||
db: db,
|
||||
rdb: rdb,
|
||||
tokenManager: tokenManager,
|
||||
app: app,
|
||||
adminToken: adminToken,
|
||||
agentToken: agentToken,
|
||||
enterprise: enterprise,
|
||||
card1: card1,
|
||||
card2: card2,
|
||||
auth1: auth1,
|
||||
shop: shop,
|
||||
agentAccount: agentAccount,
|
||||
t: t,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *authorizationTestEnv) teardown() {
|
||||
e.db.Exec("DELETE FROM tb_enterprise_card_authorization WHERE enterprise_id = ?", e.enterprise.ID)
|
||||
e.db.Exec("DELETE FROM tb_iot_card WHERE iccid LIKE 'AC%'")
|
||||
e.db.Exec("DELETE FROM tb_enterprise WHERE enterprise_code LIKE 'AE%'")
|
||||
e.db.Exec("DELETE FROM tb_account WHERE username LIKE 'aa%'")
|
||||
e.db.Exec("DELETE FROM tb_shop WHERE shop_code LIKE 'AS%'")
|
||||
|
||||
ctx := context.Background()
|
||||
testPrefix := fmt.Sprintf("test:%s:", e.t.Name())
|
||||
keys, _ := e.rdb.Keys(ctx, testPrefix+"*").Result()
|
||||
if len(keys) > 0 {
|
||||
e.rdb.Del(ctx, keys...)
|
||||
}
|
||||
|
||||
e.rdb.Close()
|
||||
}
|
||||
|
||||
func TestAuthorization_List(t *testing.T) {
|
||||
env := setupAuthorizationTestEnv(t)
|
||||
defer env.teardown()
|
||||
|
||||
t.Run("平台用户获取授权记录列表", func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "/api/admin/authorizations?page=1&page_size=20", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+env.adminToken)
|
||||
|
||||
resp, err := env.app.Test(req, -1)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, result.Code)
|
||||
|
||||
data, ok := result.Data.(map[string]interface{})
|
||||
require.True(t, ok)
|
||||
items, ok := data["items"].([]interface{})
|
||||
require.True(t, ok)
|
||||
assert.GreaterOrEqual(t, len(items), 1)
|
||||
})
|
||||
|
||||
t.Run("按企业ID筛选授权记录", func(t *testing.T) {
|
||||
url := fmt.Sprintf("/api/admin/authorizations?enterprise_id=%d&page=1&page_size=20", env.enterprise.ID)
|
||||
req := httptest.NewRequest("GET", url, nil)
|
||||
req.Header.Set("Authorization", "Bearer "+env.adminToken)
|
||||
|
||||
resp, err := env.app.Test(req, -1)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, result.Code)
|
||||
|
||||
data := result.Data.(map[string]interface{})
|
||||
total := int(data["total"].(float64))
|
||||
assert.Equal(t, 1, total)
|
||||
})
|
||||
|
||||
t.Run("按ICCID筛选授权记录", func(t *testing.T) {
|
||||
url := fmt.Sprintf("/api/admin/authorizations?iccid=%s&page=1&page_size=20", env.card1.ICCID)
|
||||
req := httptest.NewRequest("GET", url, nil)
|
||||
req.Header.Set("Authorization", "Bearer "+env.adminToken)
|
||||
|
||||
resp, err := env.app.Test(req, -1)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, result.Code)
|
||||
|
||||
data := result.Data.(map[string]interface{})
|
||||
total := int(data["total"].(float64))
|
||||
assert.Equal(t, 1, total)
|
||||
})
|
||||
|
||||
t.Run("按状态筛选-有效授权", func(t *testing.T) {
|
||||
url := fmt.Sprintf("/api/admin/authorizations?enterprise_id=%d&status=1&page=1&page_size=20", env.enterprise.ID)
|
||||
req := httptest.NewRequest("GET", url, nil)
|
||||
req.Header.Set("Authorization", "Bearer "+env.adminToken)
|
||||
|
||||
resp, err := env.app.Test(req, -1)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, result.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthorization_GetDetail(t *testing.T) {
|
||||
env := setupAuthorizationTestEnv(t)
|
||||
defer env.teardown()
|
||||
|
||||
t.Run("获取授权记录详情", func(t *testing.T) {
|
||||
url := fmt.Sprintf("/api/admin/authorizations/%d", env.auth1.ID)
|
||||
req := httptest.NewRequest("GET", url, nil)
|
||||
req.Header.Set("Authorization", "Bearer "+env.adminToken)
|
||||
|
||||
resp, err := env.app.Test(req, -1)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, result.Code)
|
||||
|
||||
data := result.Data.(map[string]interface{})
|
||||
assert.Equal(t, float64(env.auth1.ID), data["id"])
|
||||
assert.Equal(t, float64(env.enterprise.ID), data["enterprise_id"])
|
||||
assert.Equal(t, "AUTH_TEST_ENTERPRISE", data["enterprise_name"])
|
||||
assert.Equal(t, env.card1.ICCID, data["iccid"])
|
||||
assert.Equal(t, "集成测试授权记录", data["remark"])
|
||||
assert.Equal(t, float64(1), data["status"])
|
||||
})
|
||||
|
||||
t.Run("获取不存在的授权记录", func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "/api/admin/authorizations/999999", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+env.adminToken)
|
||||
|
||||
resp, err := env.app.Test(req, -1)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, 404, resp.StatusCode)
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.NotEqual(t, 0, result.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthorization_UpdateRemark(t *testing.T) {
|
||||
env := setupAuthorizationTestEnv(t)
|
||||
defer env.teardown()
|
||||
|
||||
t.Run("更新授权记录备注", func(t *testing.T) {
|
||||
url := fmt.Sprintf("/api/admin/authorizations/%d/remark", env.auth1.ID)
|
||||
body := map[string]string{"remark": "更新后的备注内容"}
|
||||
bodyBytes, _ := json.Marshal(body)
|
||||
|
||||
req := httptest.NewRequest("PUT", url, bytes.NewReader(bodyBytes))
|
||||
req.Header.Set("Authorization", "Bearer "+env.adminToken)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := env.app.Test(req, -1)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, result.Code)
|
||||
|
||||
data := result.Data.(map[string]interface{})
|
||||
assert.Equal(t, "更新后的备注内容", data["remark"])
|
||||
})
|
||||
|
||||
t.Run("更新不存在的授权记录备注", func(t *testing.T) {
|
||||
body := map[string]string{"remark": "不会更新"}
|
||||
bodyBytes, _ := json.Marshal(body)
|
||||
|
||||
req := httptest.NewRequest("PUT", "/api/admin/authorizations/999999/remark", bytes.NewReader(bodyBytes))
|
||||
req.Header.Set("Authorization", "Bearer "+env.adminToken)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := env.app.Test(req, -1)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, 404, resp.StatusCode)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthorization_DataPermission(t *testing.T) {
|
||||
env := setupAuthorizationTestEnv(t)
|
||||
defer env.teardown()
|
||||
|
||||
ts2 := time.Now().Unix() % 100000
|
||||
otherShop := &model.Shop{
|
||||
ShopName: "OTHER_TEST_SHOP",
|
||||
ShopCode: fmt.Sprintf("OS%d", ts2),
|
||||
Level: 1,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
otherShop.Creator = 1
|
||||
otherShop.Updater = 1
|
||||
require.NoError(t, env.db.Create(otherShop).Error)
|
||||
defer env.db.Exec("DELETE FROM tb_shop WHERE id = ?", otherShop.ID)
|
||||
|
||||
otherEnterprise := &model.Enterprise{
|
||||
EnterpriseName: "OTHER_TEST_ENTERPRISE",
|
||||
EnterpriseCode: fmt.Sprintf("OE%d", ts2),
|
||||
OwnerShopID: &otherShop.ID,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
otherEnterprise.Creator = 1
|
||||
otherEnterprise.Updater = 1
|
||||
require.NoError(t, env.db.Create(otherEnterprise).Error)
|
||||
defer env.db.Exec("DELETE FROM tb_enterprise WHERE id = ?", otherEnterprise.ID)
|
||||
|
||||
otherCard := &model.IotCard{
|
||||
ICCID: fmt.Sprintf("OC%d", ts2),
|
||||
MSISDN: "13800002001",
|
||||
CardType: "data_card",
|
||||
Status: 1,
|
||||
ShopID: &otherShop.ID,
|
||||
}
|
||||
require.NoError(t, env.db.Create(otherCard).Error)
|
||||
defer env.db.Exec("DELETE FROM tb_iot_card WHERE id = ?", otherCard.ID)
|
||||
|
||||
now := time.Now()
|
||||
otherAuth := &model.EnterpriseCardAuthorization{
|
||||
EnterpriseID: otherEnterprise.ID,
|
||||
CardID: otherCard.ID,
|
||||
AuthorizedBy: 1,
|
||||
AuthorizedAt: now,
|
||||
AuthorizerType: constants.UserTypePlatform,
|
||||
Remark: "其他店铺的授权记录",
|
||||
}
|
||||
require.NoError(t, env.db.Create(otherAuth).Error)
|
||||
defer env.db.Exec("DELETE FROM tb_enterprise_card_authorization WHERE id = ?", otherAuth.ID)
|
||||
|
||||
t.Run("代理用户只能看到自己店铺的授权记录", func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "/api/admin/authorizations?page=1&page_size=100", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+env.agentToken)
|
||||
|
||||
resp, err := env.app.Test(req, -1)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, result.Code)
|
||||
|
||||
data := result.Data.(map[string]interface{})
|
||||
items := data["items"].([]interface{})
|
||||
|
||||
sawOtherAuth := false
|
||||
sawOwnAuth := false
|
||||
for _, item := range items {
|
||||
itemMap := item.(map[string]interface{})
|
||||
authID := uint(itemMap["id"].(float64))
|
||||
if authID == otherAuth.ID {
|
||||
sawOtherAuth = true
|
||||
}
|
||||
if authID == env.auth1.ID {
|
||||
sawOwnAuth = true
|
||||
}
|
||||
}
|
||||
assert.False(t, sawOtherAuth, "代理用户不应该看到其他店铺的授权记录 (otherAuth.ID=%d)", otherAuth.ID)
|
||||
assert.True(t, sawOwnAuth, "代理用户应该能看到自己店铺的授权记录 (auth1.ID=%d)", env.auth1.ID)
|
||||
})
|
||||
|
||||
t.Run("平台用户可以看到所有授权记录", func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "/api/admin/authorizations?page=1&page_size=100", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+env.adminToken)
|
||||
|
||||
resp, err := env.app.Test(req, -1)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, 200, resp.StatusCode)
|
||||
|
||||
var result response.Response
|
||||
err = json.NewDecoder(resp.Body).Decode(&result)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, result.Code)
|
||||
|
||||
data := result.Data.(map[string]interface{})
|
||||
total := int(data["total"].(float64))
|
||||
assert.GreaterOrEqual(t, total, 2, "平台用户应该能看到所有授权记录")
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthorization_Unauthorized(t *testing.T) {
|
||||
env := setupAuthorizationTestEnv(t)
|
||||
defer env.teardown()
|
||||
|
||||
t.Run("无Token访问被拒绝", func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "/api/admin/authorizations", nil)
|
||||
|
||||
resp, err := env.app.Test(req, -1)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, 401, resp.StatusCode)
|
||||
})
|
||||
|
||||
t.Run("无效Token访问被拒绝", func(t *testing.T) {
|
||||
req := httptest.NewRequest("GET", "/api/admin/authorizations", nil)
|
||||
req.Header.Set("Authorization", "Bearer invalid_token")
|
||||
|
||||
resp, err := env.app.Test(req, -1)
|
||||
require.NoError(t, err)
|
||||
defer resp.Body.Close()
|
||||
|
||||
assert.Equal(t, 401, resp.StatusCode)
|
||||
})
|
||||
}
|
||||
624
tests/unit/enterprise_card_authorization_permission_test.go
Normal file
624
tests/unit/enterprise_card_authorization_permission_test.go
Normal file
@@ -0,0 +1,624 @@
|
||||
package unit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
pkggorm "github.com/break/junhong_cmp_fiber/pkg/gorm"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/internal/service/enterprise_card"
|
||||
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/tests/testutils"
|
||||
)
|
||||
|
||||
func createAgentContext(userID, shopID uint) context.Context {
|
||||
ctx := context.Background()
|
||||
ctx = context.WithValue(ctx, constants.ContextKeyUserID, userID)
|
||||
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeAgent)
|
||||
ctx = context.WithValue(ctx, constants.ContextKeyShopID, shopID)
|
||||
return ctx
|
||||
}
|
||||
|
||||
func createPlatformContext(userID uint) context.Context {
|
||||
ctx := context.Background()
|
||||
ctx = context.WithValue(ctx, constants.ContextKeyUserID, userID)
|
||||
ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypePlatform)
|
||||
ctx = context.WithValue(ctx, constants.ContextKeyShopID, uint(0))
|
||||
return ctx
|
||||
}
|
||||
|
||||
func TestAuthorizationPermission_AgentCanOnlyAuthorizeOwnCards(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
|
||||
iotCardStore := postgres.NewIotCardStore(tx, rdb)
|
||||
authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)
|
||||
|
||||
shop1ID := uint(100)
|
||||
shop2ID := uint(200)
|
||||
|
||||
ent := &model.Enterprise{
|
||||
EnterpriseName: "代理1的企业",
|
||||
EnterpriseCode: "ENT_PERM_001",
|
||||
OwnerShopID: &shop1ID,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
ent.Creator = 1
|
||||
ent.Updater = 1
|
||||
err := tx.Create(ent).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
card1 := &model.IotCard{ICCID: "PERM_CARD_001", MSISDN: "13800001001", Status: 1, ShopID: &shop1ID}
|
||||
card2 := &model.IotCard{ICCID: "PERM_CARD_002", MSISDN: "13800001002", Status: 1, ShopID: &shop2ID}
|
||||
err = tx.Create(card1).Error
|
||||
require.NoError(t, err)
|
||||
err = tx.Create(card2).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("代理可以授权自己店铺的卡", func(t *testing.T) {
|
||||
ctx := createAgentContext(1, shop1ID)
|
||||
err := authService.BatchAuthorize(ctx, enterprise_card.BatchAuthorizeRequest{
|
||||
EnterpriseID: ent.ID,
|
||||
CardIDs: []uint{card1.ID},
|
||||
AuthorizerID: 1,
|
||||
AuthorizerType: constants.UserTypeAgent,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("代理不能授权其他店铺的卡", func(t *testing.T) {
|
||||
ctx := createAgentContext(1, shop1ID)
|
||||
err := authService.BatchAuthorize(ctx, enterprise_card.BatchAuthorizeRequest{
|
||||
EnterpriseID: ent.ID,
|
||||
CardIDs: []uint{card2.ID},
|
||||
AuthorizerID: 1,
|
||||
AuthorizerType: constants.UserTypeAgent,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "不属于您的店铺")
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthorizationPermission_AgentCanOnlyAuthorizeToOwnEnterprise(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
|
||||
iotCardStore := postgres.NewIotCardStore(tx, rdb)
|
||||
authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)
|
||||
|
||||
shop1ID := uint(101)
|
||||
shop2ID := uint(201)
|
||||
|
||||
ent1 := &model.Enterprise{
|
||||
EnterpriseName: "代理1的企业",
|
||||
EnterpriseCode: "ENT_PERM_101",
|
||||
OwnerShopID: &shop1ID,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
ent1.Creator = 1
|
||||
ent1.Updater = 1
|
||||
err := tx.Create(ent1).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
ent2 := &model.Enterprise{
|
||||
EnterpriseName: "代理2的企业",
|
||||
EnterpriseCode: "ENT_PERM_201",
|
||||
OwnerShopID: &shop2ID,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
ent2.Creator = 2
|
||||
ent2.Updater = 2
|
||||
err = tx.Create(ent2).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
card := &model.IotCard{ICCID: "PERM_CARD_101", MSISDN: "13800002001", Status: 1, ShopID: &shop1ID}
|
||||
err = tx.Create(card).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("代理可以授权给自己的企业", func(t *testing.T) {
|
||||
ctx := createAgentContext(1, shop1ID)
|
||||
err := authService.BatchAuthorize(ctx, enterprise_card.BatchAuthorizeRequest{
|
||||
EnterpriseID: ent1.ID,
|
||||
CardIDs: []uint{card.ID},
|
||||
AuthorizerID: 1,
|
||||
AuthorizerType: constants.UserTypeAgent,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
card2 := &model.IotCard{ICCID: "PERM_CARD_102", MSISDN: "13800002002", Status: 1, ShopID: &shop1ID}
|
||||
err = tx.Create(card2).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("代理不能授权给其他代理的企业", func(t *testing.T) {
|
||||
ctx := createAgentContext(1, shop1ID)
|
||||
err := authService.BatchAuthorize(ctx, enterprise_card.BatchAuthorizeRequest{
|
||||
EnterpriseID: ent2.ID,
|
||||
CardIDs: []uint{card2.ID},
|
||||
AuthorizerID: 1,
|
||||
AuthorizerType: constants.UserTypeAgent,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "只能授权给自己的企业")
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthorizationPermission_PlatformCanAuthorizeAnyCard(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
|
||||
iotCardStore := postgres.NewIotCardStore(tx, rdb)
|
||||
authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)
|
||||
|
||||
shop1ID := uint(301)
|
||||
shop2ID := uint(302)
|
||||
|
||||
ent := &model.Enterprise{
|
||||
EnterpriseName: "平台测试企业",
|
||||
EnterpriseCode: "ENT_PLAT_001",
|
||||
OwnerShopID: &shop1ID,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
ent.Creator = 1
|
||||
ent.Updater = 1
|
||||
err := tx.Create(ent).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
card1 := &model.IotCard{ICCID: "PLAT_CARD_001", MSISDN: "13800003001", Status: 1, ShopID: &shop1ID}
|
||||
card2 := &model.IotCard{ICCID: "PLAT_CARD_002", MSISDN: "13800003002", Status: 1, ShopID: &shop2ID}
|
||||
err = tx.Create(card1).Error
|
||||
require.NoError(t, err)
|
||||
err = tx.Create(card2).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := createPlatformContext(1)
|
||||
|
||||
t.Run("平台可以授权任意店铺的卡", func(t *testing.T) {
|
||||
err := authService.BatchAuthorize(ctx, enterprise_card.BatchAuthorizeRequest{
|
||||
EnterpriseID: ent.ID,
|
||||
CardIDs: []uint{card1.ID, card2.ID},
|
||||
AuthorizerID: 1,
|
||||
AuthorizerType: constants.UserTypePlatform,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthorizationPermission_CannotAuthorizeBoundCard(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
|
||||
iotCardStore := postgres.NewIotCardStore(tx, rdb)
|
||||
authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)
|
||||
|
||||
shopID := uint(401)
|
||||
ent := &model.Enterprise{
|
||||
EnterpriseName: "绑定测试企业",
|
||||
EnterpriseCode: "ENT_BOUND_001",
|
||||
OwnerShopID: &shopID,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
ent.Creator = 1
|
||||
ent.Updater = 1
|
||||
err := tx.Create(ent).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
card := &model.IotCard{
|
||||
ICCID: "BOUND_CARD_001",
|
||||
MSISDN: "13800004001",
|
||||
Status: 1,
|
||||
ShopID: &shopID,
|
||||
}
|
||||
err = tx.Create(card).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
bindTime := time.Now()
|
||||
binding := &model.DeviceSimBinding{
|
||||
DeviceID: 1,
|
||||
IotCardID: card.ID,
|
||||
SlotPosition: 1,
|
||||
BindStatus: 1,
|
||||
BindTime: &bindTime,
|
||||
}
|
||||
binding.Creator = 1
|
||||
binding.Updater = 1
|
||||
err = tx.Create(binding).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := createPlatformContext(1)
|
||||
err = authService.BatchAuthorize(ctx, enterprise_card.BatchAuthorizeRequest{
|
||||
EnterpriseID: ent.ID,
|
||||
CardIDs: []uint{card.ID},
|
||||
AuthorizerID: 1,
|
||||
AuthorizerType: constants.UserTypePlatform,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "已绑定设备")
|
||||
}
|
||||
|
||||
func TestAuthorizationPermission_CannotAuthorizeUndistributedCard(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
|
||||
iotCardStore := postgres.NewIotCardStore(tx, rdb)
|
||||
authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)
|
||||
|
||||
ent := &model.Enterprise{
|
||||
EnterpriseName: "未分销测试企业",
|
||||
EnterpriseCode: "ENT_UNDIST_001",
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
ent.Creator = 1
|
||||
ent.Updater = 1
|
||||
err := tx.Create(ent).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
card := &model.IotCard{
|
||||
ICCID: "UNDIST_CARD_001",
|
||||
MSISDN: "13800005001",
|
||||
Status: 1,
|
||||
ShopID: nil,
|
||||
}
|
||||
err = tx.Create(card).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := createPlatformContext(1)
|
||||
err = authService.BatchAuthorize(ctx, enterprise_card.BatchAuthorizeRequest{
|
||||
EnterpriseID: ent.ID,
|
||||
CardIDs: []uint{card.ID},
|
||||
AuthorizerID: 1,
|
||||
AuthorizerType: constants.UserTypePlatform,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "未分销")
|
||||
}
|
||||
|
||||
func TestAuthorizationPermission_AgentCanOnlyRevokeOwnAuthorization(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
|
||||
iotCardStore := postgres.NewIotCardStore(tx, rdb)
|
||||
authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)
|
||||
|
||||
shopID := uint(501)
|
||||
ent := &model.Enterprise{
|
||||
EnterpriseName: "回收测试企业",
|
||||
EnterpriseCode: "ENT_REVOKE_001",
|
||||
OwnerShopID: &shopID,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
ent.Creator = 1
|
||||
ent.Updater = 1
|
||||
err := tx.Create(ent).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
card := &model.IotCard{ICCID: "REVOKE_CARD_001", MSISDN: "13800006001", Status: 1, ShopID: &shopID}
|
||||
err = tx.Create(card).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
now := time.Now()
|
||||
auth := &model.EnterpriseCardAuthorization{
|
||||
EnterpriseID: ent.ID,
|
||||
CardID: card.ID,
|
||||
AuthorizedBy: 1,
|
||||
AuthorizedAt: now,
|
||||
AuthorizerType: constants.UserTypeAgent,
|
||||
}
|
||||
err = authStore.Create(context.Background(), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("代理可以回收自己创建的授权", func(t *testing.T) {
|
||||
ctx := createAgentContext(1, shopID)
|
||||
err := authService.RevokeAuthorizations(ctx, enterprise_card.RevokeAuthorizationsRequest{
|
||||
EnterpriseID: ent.ID,
|
||||
CardIDs: []uint{card.ID},
|
||||
RevokedBy: 1,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
card2 := &model.IotCard{ICCID: "REVOKE_CARD_002", MSISDN: "13800006002", Status: 1, ShopID: &shopID}
|
||||
err = tx.Create(card2).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
auth2 := &model.EnterpriseCardAuthorization{
|
||||
EnterpriseID: ent.ID,
|
||||
CardID: card2.ID,
|
||||
AuthorizedBy: 999,
|
||||
AuthorizedAt: now,
|
||||
AuthorizerType: constants.UserTypeAgent,
|
||||
}
|
||||
err = authStore.Create(context.Background(), auth2)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("代理不能回收其他人创建的授权", func(t *testing.T) {
|
||||
ctx := createAgentContext(1, shopID)
|
||||
err := authService.RevokeAuthorizations(ctx, enterprise_card.RevokeAuthorizationsRequest{
|
||||
EnterpriseID: ent.ID,
|
||||
CardIDs: []uint{card2.ID},
|
||||
RevokedBy: 1,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "只能回收自己创建的授权")
|
||||
})
|
||||
|
||||
t.Run("平台可以回收任何授权", func(t *testing.T) {
|
||||
ctx := createPlatformContext(2)
|
||||
err := authService.RevokeAuthorizations(ctx, enterprise_card.RevokeAuthorizationsRequest{
|
||||
EnterpriseID: ent.ID,
|
||||
CardIDs: []uint{card2.ID},
|
||||
RevokedBy: 2,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthorizationService_ListRecords(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
|
||||
iotCardStore := postgres.NewIotCardStore(tx, rdb)
|
||||
authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)
|
||||
|
||||
shopID := uint(600)
|
||||
ent := &model.Enterprise{
|
||||
EnterpriseName: "列表测试企业",
|
||||
EnterpriseCode: "ENT_LIST_001",
|
||||
OwnerShopID: &shopID,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
ent.Creator = 1
|
||||
ent.Updater = 1
|
||||
err := tx.Create(ent).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
card1 := &model.IotCard{ICCID: "LIST_CARD_001", MSISDN: "13800007001", Status: 1, ShopID: &shopID}
|
||||
card2 := &model.IotCard{ICCID: "LIST_CARD_002", MSISDN: "13800007002", Status: 1, ShopID: &shopID}
|
||||
err = tx.Create(card1).Error
|
||||
require.NoError(t, err)
|
||||
err = tx.Create(card2).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
account := &model.Account{
|
||||
Username: "test_authorizer",
|
||||
Phone: "13800008001",
|
||||
Password: "hashed",
|
||||
UserType: constants.UserTypePlatform,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
account.Creator = 1
|
||||
account.Updater = 1
|
||||
err = tx.Create(account).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
now := time.Now()
|
||||
auth1 := &model.EnterpriseCardAuthorization{
|
||||
EnterpriseID: ent.ID,
|
||||
CardID: card1.ID,
|
||||
AuthorizedBy: account.ID,
|
||||
AuthorizedAt: now,
|
||||
AuthorizerType: constants.UserTypePlatform,
|
||||
Remark: "测试备注1",
|
||||
}
|
||||
auth2 := &model.EnterpriseCardAuthorization{
|
||||
EnterpriseID: ent.ID,
|
||||
CardID: card2.ID,
|
||||
AuthorizedBy: account.ID,
|
||||
AuthorizedAt: now,
|
||||
AuthorizerType: constants.UserTypePlatform,
|
||||
Remark: "测试备注2",
|
||||
}
|
||||
err = authStore.Create(context.Background(), auth1)
|
||||
require.NoError(t, err)
|
||||
err = authStore.Create(context.Background(), auth2)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := pkggorm.SkipDataPermission(context.Background())
|
||||
|
||||
t.Run("分页查询授权记录", func(t *testing.T) {
|
||||
resp, err := authService.ListRecords(ctx, enterprise_card.ListRecordsRequest{
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.GreaterOrEqual(t, resp.Total, int64(2))
|
||||
assert.GreaterOrEqual(t, len(resp.Items), 2)
|
||||
})
|
||||
|
||||
t.Run("按企业ID筛选", func(t *testing.T) {
|
||||
resp, err := authService.ListRecords(ctx, enterprise_card.ListRecordsRequest{
|
||||
EnterpriseID: &ent.ID,
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(2), resp.Total)
|
||||
for _, item := range resp.Items {
|
||||
assert.Equal(t, ent.ID, item.EnterpriseID)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("按ICCID筛选", func(t *testing.T) {
|
||||
resp, err := authService.ListRecords(ctx, enterprise_card.ListRecordsRequest{
|
||||
ICCID: "LIST_CARD_001",
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(1), resp.Total)
|
||||
assert.Equal(t, "LIST_CARD_001", resp.Items[0].ICCID)
|
||||
})
|
||||
|
||||
t.Run("按状态筛选-有效授权", func(t *testing.T) {
|
||||
status := 1
|
||||
resp, err := authService.ListRecords(ctx, enterprise_card.ListRecordsRequest{
|
||||
EnterpriseID: &ent.ID,
|
||||
Status: &status,
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(2), resp.Total)
|
||||
for _, item := range resp.Items {
|
||||
assert.Equal(t, 1, item.Status)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthorizationService_GetRecordDetail(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
|
||||
iotCardStore := postgres.NewIotCardStore(tx, rdb)
|
||||
authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)
|
||||
|
||||
shopID := uint(700)
|
||||
ent := &model.Enterprise{
|
||||
EnterpriseName: "详情测试企业",
|
||||
EnterpriseCode: "ENT_DETAIL_001",
|
||||
OwnerShopID: &shopID,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
ent.Creator = 1
|
||||
ent.Updater = 1
|
||||
err := tx.Create(ent).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
card := &model.IotCard{ICCID: "DETAIL_CARD_001", MSISDN: "13800009001", Status: 1, ShopID: &shopID}
|
||||
err = tx.Create(card).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
account := &model.Account{
|
||||
Username: "detail_authorizer",
|
||||
Phone: "13800009002",
|
||||
Password: "hashed",
|
||||
UserType: constants.UserTypePlatform,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
account.Creator = 1
|
||||
account.Updater = 1
|
||||
err = tx.Create(account).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
auth := &model.EnterpriseCardAuthorization{
|
||||
EnterpriseID: ent.ID,
|
||||
CardID: card.ID,
|
||||
AuthorizedBy: account.ID,
|
||||
AuthorizedAt: time.Now(),
|
||||
AuthorizerType: constants.UserTypePlatform,
|
||||
Remark: "详情测试备注",
|
||||
}
|
||||
err = authStore.Create(context.Background(), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := pkggorm.SkipDataPermission(context.Background())
|
||||
|
||||
t.Run("获取授权记录详情", func(t *testing.T) {
|
||||
detail, err := authService.GetRecordDetail(ctx, auth.ID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, auth.ID, detail.ID)
|
||||
assert.Equal(t, ent.ID, detail.EnterpriseID)
|
||||
assert.Equal(t, "详情测试企业", detail.EnterpriseName)
|
||||
assert.Equal(t, card.ID, detail.CardID)
|
||||
assert.Equal(t, "DETAIL_CARD_001", detail.ICCID)
|
||||
assert.Equal(t, "详情测试备注", detail.Remark)
|
||||
assert.Equal(t, 1, detail.Status)
|
||||
})
|
||||
|
||||
t.Run("获取不存在的记录", func(t *testing.T) {
|
||||
_, err := authService.GetRecordDetail(ctx, 99999)
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAuthorizationService_UpdateRecordRemark(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
|
||||
iotCardStore := postgres.NewIotCardStore(tx, rdb)
|
||||
authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)
|
||||
|
||||
shopID := uint(800)
|
||||
ent := &model.Enterprise{
|
||||
EnterpriseName: "备注测试企业",
|
||||
EnterpriseCode: "ENT_REMARK_001",
|
||||
OwnerShopID: &shopID,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
ent.Creator = 1
|
||||
ent.Updater = 1
|
||||
err := tx.Create(ent).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
card := &model.IotCard{ICCID: "REMARK_CARD_001", MSISDN: "13800010001", Status: 1, ShopID: &shopID}
|
||||
err = tx.Create(card).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
account := &model.Account{
|
||||
Username: "remark_authorizer",
|
||||
Phone: "13800010002",
|
||||
Password: "hashed",
|
||||
UserType: constants.UserTypePlatform,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
account.Creator = 1
|
||||
account.Updater = 1
|
||||
err = tx.Create(account).Error
|
||||
require.NoError(t, err)
|
||||
|
||||
auth := &model.EnterpriseCardAuthorization{
|
||||
EnterpriseID: ent.ID,
|
||||
CardID: card.ID,
|
||||
AuthorizedBy: account.ID,
|
||||
AuthorizedAt: time.Now(),
|
||||
AuthorizerType: constants.UserTypePlatform,
|
||||
Remark: "原始备注",
|
||||
}
|
||||
err = authStore.Create(context.Background(), auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := pkggorm.SkipDataPermission(context.Background())
|
||||
|
||||
t.Run("更新授权备注", func(t *testing.T) {
|
||||
updated, err := authService.UpdateRecordRemark(ctx, auth.ID, "更新后的备注")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "更新后的备注", updated.Remark)
|
||||
})
|
||||
|
||||
t.Run("更新不存在的记录", func(t *testing.T) {
|
||||
_, err := authService.UpdateRecordRemark(ctx, 99999, "不会更新")
|
||||
assert.Error(t, err)
|
||||
})
|
||||
}
|
||||
332
tests/unit/enterprise_card_authorization_store_test.go
Normal file
332
tests/unit/enterprise_card_authorization_store_test.go
Normal file
@@ -0,0 +1,332 @@
|
||||
package unit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/tests/testutils"
|
||||
)
|
||||
|
||||
func TestEnterpriseCardAuthorizationStore_Create(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
store := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
ctx := context.Background()
|
||||
|
||||
auth := &model.EnterpriseCardAuthorization{
|
||||
EnterpriseID: 1,
|
||||
CardID: 100,
|
||||
AuthorizedBy: 1,
|
||||
AuthorizedAt: time.Now(),
|
||||
AuthorizerType: constants.UserTypePlatform,
|
||||
}
|
||||
|
||||
err := store.Create(ctx, auth)
|
||||
require.NoError(t, err)
|
||||
assert.NotZero(t, auth.ID)
|
||||
}
|
||||
|
||||
func TestEnterpriseCardAuthorizationStore_BatchCreate(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
store := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
ctx := context.Background()
|
||||
|
||||
now := time.Now()
|
||||
auths := []*model.EnterpriseCardAuthorization{
|
||||
{
|
||||
EnterpriseID: 1,
|
||||
CardID: 101,
|
||||
AuthorizedBy: 1,
|
||||
AuthorizedAt: now,
|
||||
AuthorizerType: constants.UserTypePlatform,
|
||||
},
|
||||
{
|
||||
EnterpriseID: 1,
|
||||
CardID: 102,
|
||||
AuthorizedBy: 1,
|
||||
AuthorizedAt: now,
|
||||
AuthorizerType: constants.UserTypePlatform,
|
||||
},
|
||||
}
|
||||
|
||||
err := store.BatchCreate(ctx, auths)
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, auth := range auths {
|
||||
assert.NotZero(t, auth.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnterpriseCardAuthorizationStore_GetByEnterpriseAndCard(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
store := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
ctx := context.Background()
|
||||
|
||||
auth := &model.EnterpriseCardAuthorization{
|
||||
EnterpriseID: 2,
|
||||
CardID: 200,
|
||||
AuthorizedBy: 1,
|
||||
AuthorizedAt: time.Now(),
|
||||
AuthorizerType: constants.UserTypePlatform,
|
||||
}
|
||||
err := store.Create(ctx, auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
found, err := store.GetByEnterpriseAndCard(ctx, 2, 200)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, auth.ID, found.ID)
|
||||
assert.Equal(t, uint(2), found.EnterpriseID)
|
||||
assert.Equal(t, uint(200), found.CardID)
|
||||
|
||||
_, err = store.GetByEnterpriseAndCard(ctx, 999, 999)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestEnterpriseCardAuthorizationStore_ListByEnterprise(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
store := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
ctx := context.Background()
|
||||
|
||||
now := time.Now()
|
||||
revokedAt := time.Now()
|
||||
|
||||
auths := []*model.EnterpriseCardAuthorization{
|
||||
{EnterpriseID: 3, CardID: 301, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: constants.UserTypePlatform},
|
||||
{EnterpriseID: 3, CardID: 302, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: constants.UserTypePlatform},
|
||||
{EnterpriseID: 3, CardID: 303, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: constants.UserTypePlatform, RevokedAt: &revokedAt, RevokedBy: ptrUint(1)},
|
||||
}
|
||||
err := store.BatchCreate(ctx, auths)
|
||||
require.NoError(t, err)
|
||||
|
||||
activeAuths, err := store.ListByEnterprise(ctx, 3, false)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, activeAuths, 2)
|
||||
|
||||
allAuths, err := store.ListByEnterprise(ctx, 3, true)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, allAuths, 3)
|
||||
}
|
||||
|
||||
func TestEnterpriseCardAuthorizationStore_RevokeAuthorizations(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
store := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
ctx := context.Background()
|
||||
|
||||
now := time.Now()
|
||||
auths := []*model.EnterpriseCardAuthorization{
|
||||
{EnterpriseID: 4, CardID: 401, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: constants.UserTypePlatform},
|
||||
{EnterpriseID: 4, CardID: 402, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: constants.UserTypePlatform},
|
||||
}
|
||||
err := store.BatchCreate(ctx, auths)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = store.RevokeAuthorizations(ctx, 4, []uint{401}, 2)
|
||||
require.NoError(t, err)
|
||||
|
||||
activeAuths, err := store.ListByEnterprise(ctx, 4, false)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, activeAuths, 1)
|
||||
assert.Equal(t, uint(402), activeAuths[0].CardID)
|
||||
|
||||
allAuths, err := store.ListByEnterprise(ctx, 4, true)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, allAuths, 2)
|
||||
}
|
||||
|
||||
func TestEnterpriseCardAuthorizationStore_GetActiveAuthorizedCardIDs(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
store := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
ctx := context.Background()
|
||||
|
||||
now := time.Now()
|
||||
revokedAt := time.Now()
|
||||
auths := []*model.EnterpriseCardAuthorization{
|
||||
{EnterpriseID: 5, CardID: 501, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: constants.UserTypePlatform},
|
||||
{EnterpriseID: 5, CardID: 502, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: constants.UserTypePlatform},
|
||||
{EnterpriseID: 5, CardID: 503, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: constants.UserTypePlatform, RevokedAt: &revokedAt, RevokedBy: ptrUint(1)},
|
||||
}
|
||||
err := store.BatchCreate(ctx, auths)
|
||||
require.NoError(t, err)
|
||||
|
||||
cardIDs, err := store.GetActiveAuthorizedCardIDs(ctx, 5)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, cardIDs, 2)
|
||||
assert.Contains(t, cardIDs, uint(501))
|
||||
assert.Contains(t, cardIDs, uint(502))
|
||||
assert.NotContains(t, cardIDs, uint(503))
|
||||
}
|
||||
|
||||
func TestEnterpriseCardAuthorizationStore_CheckAuthorizationExists(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
store := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
ctx := context.Background()
|
||||
|
||||
auth := &model.EnterpriseCardAuthorization{
|
||||
EnterpriseID: 6,
|
||||
CardID: 600,
|
||||
AuthorizedBy: 1,
|
||||
AuthorizedAt: time.Now(),
|
||||
AuthorizerType: constants.UserTypePlatform,
|
||||
}
|
||||
err := store.Create(ctx, auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
exists, err := store.CheckAuthorizationExists(ctx, 6, 600)
|
||||
require.NoError(t, err)
|
||||
assert.True(t, exists)
|
||||
|
||||
exists, err = store.CheckAuthorizationExists(ctx, 6, 999)
|
||||
require.NoError(t, err)
|
||||
assert.False(t, exists)
|
||||
}
|
||||
|
||||
func TestEnterpriseCardAuthorizationStore_GetActiveAuthsByCardIDs(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
store := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
ctx := context.Background()
|
||||
|
||||
now := time.Now()
|
||||
auths := []*model.EnterpriseCardAuthorization{
|
||||
{EnterpriseID: 7, CardID: 701, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: constants.UserTypePlatform},
|
||||
{EnterpriseID: 7, CardID: 702, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: constants.UserTypePlatform},
|
||||
}
|
||||
err := store.BatchCreate(ctx, auths)
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := store.GetActiveAuthsByCardIDs(ctx, 7, []uint{701, 702, 703})
|
||||
require.NoError(t, err)
|
||||
assert.True(t, result[701])
|
||||
assert.True(t, result[702])
|
||||
assert.False(t, result[703])
|
||||
}
|
||||
|
||||
func TestEnterpriseCardAuthorizationStore_ListWithOptions(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
store := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
ctx := context.Background()
|
||||
|
||||
now := time.Now()
|
||||
for i := uint(0); i < 15; i++ {
|
||||
auth := &model.EnterpriseCardAuthorization{
|
||||
EnterpriseID: 8,
|
||||
CardID: 800 + i,
|
||||
AuthorizedBy: 1,
|
||||
AuthorizedAt: now,
|
||||
AuthorizerType: constants.UserTypePlatform,
|
||||
}
|
||||
err := store.Create(ctx, auth)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
enterpriseID := uint(8)
|
||||
opts := postgres.AuthorizationListOptions{
|
||||
EnterpriseID: &enterpriseID,
|
||||
Limit: 10,
|
||||
Offset: 0,
|
||||
}
|
||||
auths, total, err := store.ListWithOptions(ctx, opts)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(15), total)
|
||||
assert.Len(t, auths, 10)
|
||||
|
||||
opts.Offset = 10
|
||||
auths, total, err = store.ListWithOptions(ctx, opts)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(15), total)
|
||||
assert.Len(t, auths, 5)
|
||||
}
|
||||
|
||||
func ptrUint(v uint) *uint {
|
||||
return &v
|
||||
}
|
||||
|
||||
func TestEnterpriseCardAuthorizationStore_UpdateRemark(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
store := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
ctx := context.Background()
|
||||
|
||||
auth := &model.EnterpriseCardAuthorization{
|
||||
EnterpriseID: 10,
|
||||
CardID: 1000,
|
||||
AuthorizedBy: 1,
|
||||
AuthorizedAt: time.Now(),
|
||||
AuthorizerType: constants.UserTypePlatform,
|
||||
Remark: "原始备注",
|
||||
}
|
||||
err := store.Create(ctx, auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = store.UpdateRemark(ctx, auth.ID, "更新后的备注")
|
||||
require.NoError(t, err)
|
||||
|
||||
updated, err := store.GetByID(ctx, auth.ID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "更新后的备注", updated.Remark)
|
||||
|
||||
err = store.UpdateRemark(ctx, 99999, "不存在的记录")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestEnterpriseCardAuthorizationStore_GetByID(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
rdb := testutils.GetTestRedis(t)
|
||||
testutils.CleanTestRedisKeys(t, rdb)
|
||||
|
||||
store := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
|
||||
ctx := context.Background()
|
||||
|
||||
auth := &model.EnterpriseCardAuthorization{
|
||||
EnterpriseID: 11,
|
||||
CardID: 1100,
|
||||
AuthorizedBy: 1,
|
||||
AuthorizedAt: time.Now(),
|
||||
AuthorizerType: constants.UserTypePlatform,
|
||||
}
|
||||
err := store.Create(ctx, auth)
|
||||
require.NoError(t, err)
|
||||
|
||||
found, err := store.GetByID(ctx, auth.ID)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, auth.ID, found.ID)
|
||||
assert.Equal(t, uint(11), found.EnterpriseID)
|
||||
assert.Equal(t, uint(1100), found.CardID)
|
||||
|
||||
_, err = store.GetByID(ctx, 99999)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
@@ -227,7 +227,7 @@ func TestEnterpriseCardService_AllocateCards(t *testing.T) {
|
||||
|
||||
var count int64
|
||||
tx.Model(&model.EnterpriseCardAuthorization{}).
|
||||
Where("enterprise_id = ? AND iot_card_id = ?", ent.ID, card.ID).
|
||||
Where("enterprise_id = ? AND card_id = ?", ent.ID, card.ID).
|
||||
Count(&count)
|
||||
assert.Equal(t, int64(1), count)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user