2025-09-21 18:27:25 +08:00
|
|
|
|
package service
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"context"
|
2025-09-30 17:44:18 +08:00
|
|
|
|
"tydata-server/app/main/api/internal/config"
|
|
|
|
|
|
"tydata-server/app/main/model"
|
2025-09-21 18:27:25 +08:00
|
|
|
|
"database/sql"
|
|
|
|
|
|
"errors"
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"os"
|
|
|
|
|
|
"path/filepath"
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
"testing"
|
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/Masterminds/squirrel"
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
|
"github.com/stretchr/testify/mock"
|
|
|
|
|
|
"github.com/zeromicro/go-zero/core/stores/sqlx"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// mockResult 模拟sql.Result
|
|
|
|
|
|
type mockResult struct {
|
|
|
|
|
|
lastInsertId int64
|
|
|
|
|
|
rowsAffected int64
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *mockResult) LastInsertId() (int64, error) {
|
|
|
|
|
|
return m.lastInsertId, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *mockResult) RowsAffected() (int64, error) {
|
|
|
|
|
|
return m.rowsAffected, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// MockAuthorizationDocumentModel 模拟授权书模型
|
|
|
|
|
|
type MockAuthorizationDocumentModel struct {
|
|
|
|
|
|
mock.Mock
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockAuthorizationDocumentModel) Insert(ctx context.Context, session sqlx.Session, data *model.AuthorizationDocument) (sql.Result, error) {
|
|
|
|
|
|
args := m.Called(ctx, session, data)
|
|
|
|
|
|
return args.Get(0).(sql.Result), args.Error(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockAuthorizationDocumentModel) FindOne(ctx context.Context, id int64) (*model.AuthorizationDocument, error) {
|
|
|
|
|
|
args := m.Called(ctx, id)
|
|
|
|
|
|
if args.Get(0) == nil {
|
|
|
|
|
|
return nil, args.Error(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
return args.Get(0).(*model.AuthorizationDocument), args.Error(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockAuthorizationDocumentModel) Update(ctx context.Context, session sqlx.Session, data *model.AuthorizationDocument) (sql.Result, error) {
|
|
|
|
|
|
args := m.Called(ctx, session, data)
|
|
|
|
|
|
return args.Get(0).(sql.Result), args.Error(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockAuthorizationDocumentModel) UpdateWithVersion(ctx context.Context, session sqlx.Session, data *model.AuthorizationDocument) error {
|
|
|
|
|
|
args := m.Called(ctx, session, data)
|
|
|
|
|
|
return args.Error(0)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockAuthorizationDocumentModel) Trans(ctx context.Context, fn func(context.Context, sqlx.Session) error) error {
|
|
|
|
|
|
args := m.Called(ctx, fn)
|
|
|
|
|
|
return args.Error(0)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockAuthorizationDocumentModel) SelectBuilder() squirrel.SelectBuilder {
|
|
|
|
|
|
args := m.Called()
|
|
|
|
|
|
return args.Get(0).(squirrel.SelectBuilder)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockAuthorizationDocumentModel) DeleteSoft(ctx context.Context, session sqlx.Session, data *model.AuthorizationDocument) error {
|
|
|
|
|
|
args := m.Called(ctx, session, data)
|
|
|
|
|
|
return args.Error(0)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockAuthorizationDocumentModel) FindSum(ctx context.Context, sumBuilder squirrel.SelectBuilder, field string) (float64, error) {
|
|
|
|
|
|
args := m.Called(ctx, sumBuilder, field)
|
|
|
|
|
|
return args.Get(0).(float64), args.Error(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockAuthorizationDocumentModel) FindCount(ctx context.Context, countBuilder squirrel.SelectBuilder, field string) (int64, error) {
|
|
|
|
|
|
args := m.Called(ctx, countBuilder, field)
|
|
|
|
|
|
return args.Get(0).(int64), args.Error(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockAuthorizationDocumentModel) FindAll(ctx context.Context, rowBuilder squirrel.SelectBuilder, orderBy string) ([]*model.AuthorizationDocument, error) {
|
|
|
|
|
|
args := m.Called(ctx, rowBuilder, orderBy)
|
|
|
|
|
|
if args.Get(0) == nil {
|
|
|
|
|
|
return nil, args.Error(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
return args.Get(0).([]*model.AuthorizationDocument), args.Error(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockAuthorizationDocumentModel) FindPageListByPage(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*model.AuthorizationDocument, error) {
|
|
|
|
|
|
args := m.Called(ctx, rowBuilder, page, pageSize, orderBy)
|
|
|
|
|
|
if args.Get(0) == nil {
|
|
|
|
|
|
return nil, args.Error(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
return args.Get(0).([]*model.AuthorizationDocument), args.Error(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockAuthorizationDocumentModel) FindPageListByPageWithTotal(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*model.AuthorizationDocument, int64, error) {
|
|
|
|
|
|
args := m.Called(ctx, rowBuilder, page, pageSize, orderBy)
|
|
|
|
|
|
if args.Get(0) == nil {
|
|
|
|
|
|
return nil, args.Get(1).(int64), args.Error(2)
|
|
|
|
|
|
}
|
|
|
|
|
|
return args.Get(0).([]*model.AuthorizationDocument), args.Get(1).(int64), args.Error(2)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockAuthorizationDocumentModel) FindPageListByIdDESC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMinId, pageSize int64) ([]*model.AuthorizationDocument, error) {
|
|
|
|
|
|
args := m.Called(ctx, rowBuilder, preMinId, pageSize)
|
|
|
|
|
|
if args.Get(0) == nil {
|
|
|
|
|
|
return nil, args.Error(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
return args.Get(0).([]*model.AuthorizationDocument), args.Error(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockAuthorizationDocumentModel) FindPageListByIdASC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMaxId, pageSize int64) ([]*model.AuthorizationDocument, error) {
|
|
|
|
|
|
args := m.Called(ctx, rowBuilder, preMaxId, pageSize)
|
|
|
|
|
|
if args.Get(0) == nil {
|
|
|
|
|
|
return nil, args.Error(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
return args.Get(0).([]*model.AuthorizationDocument), args.Error(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockAuthorizationDocumentModel) Delete(ctx context.Context, session sqlx.Session, id int64) error {
|
|
|
|
|
|
args := m.Called(ctx, session, id)
|
|
|
|
|
|
return args.Error(0)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockAuthorizationDocumentModel) FindByOrderId(ctx context.Context, orderId int64) ([]*model.AuthorizationDocument, error) {
|
|
|
|
|
|
args := m.Called(ctx, orderId)
|
|
|
|
|
|
if args.Get(0) == nil {
|
|
|
|
|
|
return nil, args.Error(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
return args.Get(0).([]*model.AuthorizationDocument), args.Error(1)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// MockResult 模拟数据库结果
|
|
|
|
|
|
type MockResult struct {
|
|
|
|
|
|
lastInsertId int64
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockResult) LastInsertId() (int64, error) {
|
|
|
|
|
|
return m.lastInsertId, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (m *MockResult) RowsAffected() (int64, error) {
|
|
|
|
|
|
return 1, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TestNewAuthorizationService 测试创建授权书服务
|
|
|
|
|
|
func TestNewAuthorizationService(t *testing.T) {
|
|
|
|
|
|
config := config.Config{
|
|
|
|
|
|
Authorization: config.AuthorizationConfig{
|
|
|
|
|
|
FileBaseURL: "https://test.com/api/v1/auth-docs",
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
mockModel := &MockAuthorizationDocumentModel{}
|
|
|
|
|
|
|
|
|
|
|
|
service := NewAuthorizationService(config, mockModel)
|
|
|
|
|
|
|
|
|
|
|
|
assert.NotNil(t, service)
|
|
|
|
|
|
assert.Equal(t, "data/authorization_docs", service.fileStoragePath)
|
|
|
|
|
|
assert.Equal(t, "https://test.com/api/v1/auth-docs", service.fileBaseURL)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TestGetFullFileURL 测试获取完整文件URL
|
|
|
|
|
|
func TestGetFullFileURL(t *testing.T) {
|
|
|
|
|
|
config := config.Config{
|
|
|
|
|
|
Authorization: config.AuthorizationConfig{
|
|
|
|
|
|
FileBaseURL: "https://test.com/api/v1/auth-docs",
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
mockModel := &MockAuthorizationDocumentModel{}
|
|
|
|
|
|
service := NewAuthorizationService(config, mockModel)
|
|
|
|
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
|
|
name string
|
|
|
|
|
|
relativePath string
|
|
|
|
|
|
expected string
|
|
|
|
|
|
}{
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "正常相对路径",
|
|
|
|
|
|
relativePath: "2025/09/auth_123_456_20250913_160800.pdf",
|
|
|
|
|
|
expected: "https://test.com/api/v1/auth-docs/2025/09/auth_123_456_20250913_160800.pdf",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "空路径",
|
|
|
|
|
|
relativePath: "",
|
|
|
|
|
|
expected: "",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "只有文件名",
|
|
|
|
|
|
relativePath: "test.pdf",
|
|
|
|
|
|
expected: "https://test.com/api/v1/auth-docs/test.pdf",
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
|
result := service.GetFullFileURL(tt.relativePath)
|
|
|
|
|
|
assert.Equal(t, tt.expected, result)
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TestGenerateAuthorizationDocument 测试生成授权书
|
|
|
|
|
|
func TestGenerateAuthorizationDocument(t *testing.T) {
|
|
|
|
|
|
// 创建测试配置
|
|
|
|
|
|
config := config.Config{
|
|
|
|
|
|
Authorization: config.AuthorizationConfig{
|
|
|
|
|
|
FileBaseURL: "https://test.example.com/api/v1/auth-docs",
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建模拟的数据库模型
|
|
|
|
|
|
mockModel := &MockAuthorizationDocumentModel{}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建授权书服务
|
|
|
|
|
|
service := NewAuthorizationService(config, mockModel)
|
|
|
|
|
|
|
|
|
|
|
|
// 准备测试数据
|
|
|
|
|
|
userInfo := map[string]interface{}{
|
|
|
|
|
|
"name": "张三",
|
|
|
|
|
|
"id_card": "110101199001011234",
|
|
|
|
|
|
"mobile": "13800138000",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 模拟数据库插入成功
|
|
|
|
|
|
mockModel.On("Insert", mock.Anything, mock.Anything, mock.Anything).Return(
|
|
|
|
|
|
&mockResult{lastInsertId: 1, rowsAffected: 1}, nil)
|
|
|
|
|
|
|
|
|
|
|
|
// 执行测试
|
|
|
|
|
|
authDoc, err := service.GenerateAuthorizationDocument(
|
|
|
|
|
|
context.Background(),
|
|
|
|
|
|
1, // userID
|
|
|
|
|
|
2, // orderID
|
|
|
|
|
|
3, // queryID
|
|
|
|
|
|
userInfo,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证结果
|
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
assert.NotNil(t, authDoc)
|
|
|
|
|
|
assert.Equal(t, int64(1), authDoc.UserId)
|
|
|
|
|
|
assert.Equal(t, int64(2), authDoc.OrderId)
|
|
|
|
|
|
assert.Equal(t, int64(3), authDoc.QueryId)
|
|
|
|
|
|
assert.Equal(t, "pdf", authDoc.FileType)
|
|
|
|
|
|
assert.Equal(t, "active", authDoc.Status)
|
|
|
|
|
|
assert.False(t, authDoc.ExpireTime.Valid) // 永久保留,不设置过期时间
|
|
|
|
|
|
|
|
|
|
|
|
// 验证文件路径格式(兼容Windows和Unix路径分隔符)
|
|
|
|
|
|
assert.True(t, strings.Contains(authDoc.FilePath, "data/authorization_docs") ||
|
|
|
|
|
|
strings.Contains(authDoc.FilePath, "data\\authorization_docs"))
|
|
|
|
|
|
assert.Contains(t, authDoc.FileName, "auth_")
|
|
|
|
|
|
assert.Contains(t, authDoc.FileName, ".pdf")
|
|
|
|
|
|
|
|
|
|
|
|
// 验证相对路径格式
|
|
|
|
|
|
assert.Regexp(t, `^\d{4}/\d{2}/auth_\d+_\d+_\d{8}_\d{6}\.pdf$`, authDoc.FileUrl)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证文件大小
|
|
|
|
|
|
assert.Greater(t, authDoc.FileSize, int64(0))
|
|
|
|
|
|
|
|
|
|
|
|
// 验证数据库调用
|
|
|
|
|
|
mockModel.AssertExpectations(t)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证文件是否真的被创建
|
|
|
|
|
|
if _, err := os.Stat(authDoc.FilePath); err == nil {
|
|
|
|
|
|
t.Logf("✅ 授权书文件已创建: %s", authDoc.FilePath)
|
|
|
|
|
|
t.Logf("📊 文件大小: %d 字节", authDoc.FileSize)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
t.Logf("⚠️ 文件未找到: %s", authDoc.FilePath)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TestGenerateAuthorizationDocument_DatabaseError 测试数据库错误
|
|
|
|
|
|
func TestGenerateAuthorizationDocument_DatabaseError(t *testing.T) {
|
|
|
|
|
|
// 创建测试配置
|
|
|
|
|
|
config := config.Config{
|
|
|
|
|
|
Authorization: config.AuthorizationConfig{
|
|
|
|
|
|
FileBaseURL: "https://test.example.com/api/v1/auth-docs",
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建模拟的数据库模型
|
|
|
|
|
|
mockModel := &MockAuthorizationDocumentModel{}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建授权书服务
|
|
|
|
|
|
service := NewAuthorizationService(config, mockModel)
|
|
|
|
|
|
|
|
|
|
|
|
// 准备测试数据
|
|
|
|
|
|
userInfo := map[string]interface{}{
|
|
|
|
|
|
"name": "李四",
|
|
|
|
|
|
"id_card": "110101199001011235",
|
|
|
|
|
|
"mobile": "13800138001",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 模拟数据库插入失败
|
|
|
|
|
|
mockModel.On("Insert", mock.Anything, mock.Anything, mock.Anything).Return(
|
|
|
|
|
|
(*mockResult)(nil), errors.New("数据库连接失败"))
|
|
|
|
|
|
|
|
|
|
|
|
// 执行测试
|
|
|
|
|
|
authDoc, err := service.GenerateAuthorizationDocument(
|
|
|
|
|
|
context.Background(),
|
|
|
|
|
|
1, // userID
|
|
|
|
|
|
2, // orderID
|
|
|
|
|
|
3, // queryID
|
|
|
|
|
|
userInfo,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证结果
|
|
|
|
|
|
assert.Error(t, err)
|
|
|
|
|
|
assert.Nil(t, authDoc)
|
|
|
|
|
|
assert.Contains(t, err.Error(), "数据库连接失败")
|
|
|
|
|
|
|
|
|
|
|
|
// 验证数据库调用
|
|
|
|
|
|
mockModel.AssertExpectations(t)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TestGeneratePDFContent 测试生成PDF内容
|
|
|
|
|
|
func TestGeneratePDFContent(t *testing.T) {
|
|
|
|
|
|
config := config.Config{
|
|
|
|
|
|
Authorization: config.AuthorizationConfig{
|
|
|
|
|
|
FileBaseURL: "https://test.com/api/v1/auth-docs",
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
mockModel := &MockAuthorizationDocumentModel{}
|
|
|
|
|
|
service := NewAuthorizationService(config, mockModel)
|
|
|
|
|
|
|
|
|
|
|
|
userInfo := map[string]interface{}{
|
|
|
|
|
|
"name": "张三",
|
|
|
|
|
|
"id_card": "110101199001011234",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pdfBytes, err := service.generatePDFContent(userInfo)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证结果
|
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
assert.NotNil(t, pdfBytes)
|
|
|
|
|
|
assert.Greater(t, len(pdfBytes), 0)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证PDF内容(PDF是二进制格式,只验证基本结构)
|
|
|
|
|
|
assert.Contains(t, string(pdfBytes), "%PDF") // PDF文件头
|
|
|
|
|
|
|
|
|
|
|
|
// 按照 GenerateAuthorizationDocument 的方式保存文件到本地
|
|
|
|
|
|
// 1. 创建文件存储目录
|
|
|
|
|
|
year := time.Now().Format("2006")
|
|
|
|
|
|
month := time.Now().Format("01")
|
|
|
|
|
|
dirPath := filepath.Join("data", "authorization_docs", year, month)
|
|
|
|
|
|
if err := os.MkdirAll(dirPath, 0755); err != nil {
|
|
|
|
|
|
t.Fatalf("创建存储目录失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 生成文件名和路径
|
|
|
|
|
|
fileName := fmt.Sprintf("test_auth_%s.pdf", time.Now().Format("20060102_150405"))
|
|
|
|
|
|
filePath := filepath.Join(dirPath, fileName)
|
|
|
|
|
|
relativePath := fmt.Sprintf("%s/%s/%s", year, month, fileName)
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 保存PDF文件
|
|
|
|
|
|
if err := os.WriteFile(filePath, pdfBytes, 0644); err != nil {
|
|
|
|
|
|
t.Fatalf("保存PDF文件失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 验证文件是否保存成功
|
|
|
|
|
|
if _, err := os.Stat(filePath); err == nil {
|
|
|
|
|
|
t.Logf("✅ PDF文件已保存到本地")
|
|
|
|
|
|
t.Logf("📄 文件名: %s", fileName)
|
|
|
|
|
|
t.Logf("📁 文件路径: %s", filePath)
|
|
|
|
|
|
t.Logf("🔗 相对路径: %s", relativePath)
|
|
|
|
|
|
t.Logf("📊 文件大小: %d 字节", len(pdfBytes))
|
|
|
|
|
|
|
|
|
|
|
|
// 获取绝对路径
|
|
|
|
|
|
absPath, _ := filepath.Abs(filePath)
|
|
|
|
|
|
t.Logf("📍 绝对路径: %s", absPath)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
t.Errorf("❌ PDF文件保存失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TestSavePDFToLocal 专门测试保存PDF文件到本地
|
|
|
|
|
|
func TestSavePDFToLocal(t *testing.T) {
|
|
|
|
|
|
config := config.Config{
|
|
|
|
|
|
Authorization: config.AuthorizationConfig{
|
|
|
|
|
|
FileBaseURL: "https://test.com/api/v1/auth-docs",
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
mockModel := &MockAuthorizationDocumentModel{}
|
|
|
|
|
|
service := NewAuthorizationService(config, mockModel)
|
|
|
|
|
|
|
|
|
|
|
|
// 准备测试数据
|
|
|
|
|
|
userInfo := map[string]interface{}{
|
|
|
|
|
|
"name": "何志勇",
|
|
|
|
|
|
"id_card": "452528197907133014",
|
|
|
|
|
|
"mobile": "18276151590",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 生成PDF内容
|
|
|
|
|
|
pdfBytes, err := service.generatePDFContent(userInfo)
|
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
assert.NotNil(t, pdfBytes)
|
|
|
|
|
|
assert.Greater(t, len(pdfBytes), 0)
|
|
|
|
|
|
|
|
|
|
|
|
// 按照 GenerateAuthorizationDocument 的方式保存文件到本地
|
|
|
|
|
|
// 1. 创建文件存储目录
|
|
|
|
|
|
year := time.Now().Format("2006")
|
|
|
|
|
|
month := time.Now().Format("01")
|
|
|
|
|
|
dirPath := filepath.Join("data", "authorization_docs", year, month)
|
|
|
|
|
|
if err := os.MkdirAll(dirPath, 0755); err != nil {
|
|
|
|
|
|
t.Fatalf("创建存储目录失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 生成文件名和路径
|
|
|
|
|
|
fileName := fmt.Sprintf("local_test_auth_%s.pdf", time.Now().Format("20060102_150405"))
|
|
|
|
|
|
filePath := filepath.Join(dirPath, fileName)
|
|
|
|
|
|
relativePath := fmt.Sprintf("%s/%s/%s", year, month, fileName)
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 保存PDF文件
|
|
|
|
|
|
if err := os.WriteFile(filePath, pdfBytes, 0644); err != nil {
|
|
|
|
|
|
t.Fatalf("保存PDF文件失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 验证文件是否保存成功
|
|
|
|
|
|
if _, err := os.Stat(filePath); err == nil {
|
|
|
|
|
|
t.Logf("✅ PDF文件已保存到本地")
|
|
|
|
|
|
t.Logf("📄 文件名: %s", fileName)
|
|
|
|
|
|
t.Logf("📁 文件路径: %s", filePath)
|
|
|
|
|
|
t.Logf("🔗 相对路径: %s", relativePath)
|
|
|
|
|
|
t.Logf("📊 文件大小: %d 字节", len(pdfBytes))
|
|
|
|
|
|
|
|
|
|
|
|
// 获取绝对路径
|
|
|
|
|
|
absPath, _ := filepath.Abs(filePath)
|
|
|
|
|
|
t.Logf("📍 绝对路径: %s", absPath)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证文件内容
|
|
|
|
|
|
fileInfo, err := os.Stat(filePath)
|
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
assert.Greater(t, fileInfo.Size(), int64(1000)) // 文件应该大于1KB
|
|
|
|
|
|
|
|
|
|
|
|
t.Logf("🎉 文件保存验证通过!")
|
|
|
|
|
|
} else {
|
|
|
|
|
|
t.Errorf("❌ PDF文件保存失败: %v", err)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TestGeneratePDFContent_EmptyUserInfo 测试空用户信息
|
|
|
|
|
|
func TestGeneratePDFContent_EmptyUserInfo(t *testing.T) {
|
|
|
|
|
|
config := config.Config{
|
|
|
|
|
|
Authorization: config.AuthorizationConfig{
|
|
|
|
|
|
FileBaseURL: "https://test.com/api/v1/auth-docs",
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
mockModel := &MockAuthorizationDocumentModel{}
|
|
|
|
|
|
service := NewAuthorizationService(config, mockModel)
|
|
|
|
|
|
|
|
|
|
|
|
userInfo := map[string]interface{}{}
|
|
|
|
|
|
|
|
|
|
|
|
pdfBytes, err := service.generatePDFContent(userInfo)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证结果
|
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
assert.NotNil(t, pdfBytes)
|
|
|
|
|
|
assert.Greater(t, len(pdfBytes), 0)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证PDF内容(PDF是二进制格式,只验证基本结构)
|
|
|
|
|
|
assert.Contains(t, string(pdfBytes), "%PDF") // PDF文件头
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TestGetUserInfoString 测试获取用户信息字符串
|
|
|
|
|
|
func TestGetUserInfoString(t *testing.T) {
|
|
|
|
|
|
userInfo := map[string]interface{}{
|
|
|
|
|
|
"name": "张三",
|
|
|
|
|
|
"id_card": "110101199001011234",
|
|
|
|
|
|
"age": 30,
|
|
|
|
|
|
"empty": "",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
|
|
name string
|
|
|
|
|
|
key string
|
|
|
|
|
|
expected string
|
|
|
|
|
|
}{
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "正常字符串",
|
|
|
|
|
|
key: "name",
|
|
|
|
|
|
expected: "张三",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "身份证号",
|
|
|
|
|
|
key: "id_card",
|
|
|
|
|
|
expected: "110101199001011234",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "空字符串",
|
|
|
|
|
|
key: "empty",
|
|
|
|
|
|
expected: "",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "不存在的键",
|
|
|
|
|
|
key: "not_exist",
|
|
|
|
|
|
expected: "",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "非字符串类型",
|
|
|
|
|
|
key: "age",
|
|
|
|
|
|
expected: "",
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
|
result := getUserInfoString(userInfo, tt.key)
|
|
|
|
|
|
assert.Equal(t, tt.expected, result)
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// BenchmarkGeneratePDFContent 性能测试
|
|
|
|
|
|
func BenchmarkGeneratePDFContent(b *testing.B) {
|
|
|
|
|
|
config := config.Config{
|
|
|
|
|
|
Authorization: config.AuthorizationConfig{
|
|
|
|
|
|
FileBaseURL: "https://test.com/api/v1/auth-docs",
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
mockModel := &MockAuthorizationDocumentModel{}
|
|
|
|
|
|
service := NewAuthorizationService(config, mockModel)
|
|
|
|
|
|
|
|
|
|
|
|
userInfo := map[string]interface{}{
|
|
|
|
|
|
"name": "张三",
|
|
|
|
|
|
"id_card": "110101199001011234",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
b.ResetTimer()
|
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
|
|
_, err := service.generatePDFContent(userInfo)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
b.Fatal(err)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TestAuthorizationService_Integration 集成测试(需要真实文件系统)
|
|
|
|
|
|
func TestAuthorizationService_Integration(t *testing.T) {
|
|
|
|
|
|
// 创建测试配置
|
|
|
|
|
|
config := config.Config{
|
|
|
|
|
|
Authorization: config.AuthorizationConfig{
|
|
|
|
|
|
FileBaseURL: "https://test.example.com/api/v1/auth-docs",
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建模拟的数据库模型
|
|
|
|
|
|
mockModel := &MockAuthorizationDocumentModel{}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建授权书服务
|
|
|
|
|
|
service := NewAuthorizationService(config, mockModel)
|
|
|
|
|
|
|
|
|
|
|
|
// 准备测试数据
|
|
|
|
|
|
userInfo := map[string]interface{}{
|
|
|
|
|
|
"name": "王五",
|
|
|
|
|
|
"id_card": "110101199001011236",
|
|
|
|
|
|
"mobile": "13800138002",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 模拟数据库插入成功
|
|
|
|
|
|
mockModel.On("Insert", mock.Anything, mock.Anything, mock.Anything).Return(
|
|
|
|
|
|
&mockResult{lastInsertId: 1, rowsAffected: 1}, nil)
|
|
|
|
|
|
|
|
|
|
|
|
// 执行测试
|
|
|
|
|
|
authDoc, err := service.GenerateAuthorizationDocument(
|
|
|
|
|
|
context.Background(),
|
|
|
|
|
|
1, // userID
|
|
|
|
|
|
2, // orderID
|
|
|
|
|
|
3, // queryID
|
|
|
|
|
|
userInfo,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证结果
|
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
assert.NotNil(t, authDoc)
|
|
|
|
|
|
|
|
|
|
|
|
// 测试GetFullFileURL方法
|
|
|
|
|
|
fullURL := service.GetFullFileURL(authDoc.FileUrl)
|
|
|
|
|
|
expectedURL := fmt.Sprintf("%s/%s", config.Authorization.FileBaseURL, authDoc.FileUrl)
|
|
|
|
|
|
assert.Equal(t, expectedURL, fullURL)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证文件是否真的被创建
|
|
|
|
|
|
if _, err := os.Stat(authDoc.FilePath); err == nil {
|
|
|
|
|
|
t.Logf("✅ 集成测试成功 - 授权书文件已创建")
|
|
|
|
|
|
t.Logf("📄 文件名: %s", authDoc.FileName)
|
|
|
|
|
|
t.Logf("📁 文件路径: %s", authDoc.FilePath)
|
|
|
|
|
|
t.Logf("🔗 相对路径: %s", authDoc.FileUrl)
|
|
|
|
|
|
t.Logf("🌐 完整URL: %s", fullURL)
|
|
|
|
|
|
t.Logf("📊 文件大小: %d 字节", authDoc.FileSize)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
t.Logf("⚠️ 集成测试 - 文件未找到: %s", authDoc.FilePath)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证数据库调用
|
|
|
|
|
|
mockModel.AssertExpectations(t)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// TestGeneratePDFFile 专门测试PDF文件生成
|
|
|
|
|
|
func TestGeneratePDFFile(t *testing.T) {
|
|
|
|
|
|
// 创建测试配置
|
|
|
|
|
|
config := config.Config{
|
|
|
|
|
|
Authorization: config.AuthorizationConfig{
|
|
|
|
|
|
FileBaseURL: "https://test.example.com/api/v1/auth-docs",
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建模拟的数据库模型
|
|
|
|
|
|
mockModel := &MockAuthorizationDocumentModel{}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建授权书服务
|
|
|
|
|
|
service := NewAuthorizationService(config, mockModel)
|
|
|
|
|
|
|
|
|
|
|
|
// 准备测试数据
|
|
|
|
|
|
userInfo := map[string]interface{}{
|
|
|
|
|
|
"name": "测试用户",
|
|
|
|
|
|
"id_card": "110101199001011237",
|
|
|
|
|
|
"mobile": "13800138003",
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 模拟数据库插入成功
|
|
|
|
|
|
mockModel.On("Insert", mock.Anything, mock.Anything, mock.Anything).Return(
|
|
|
|
|
|
&mockResult{lastInsertId: 1, rowsAffected: 1}, nil)
|
|
|
|
|
|
|
|
|
|
|
|
// 执行测试
|
|
|
|
|
|
authDoc, err := service.GenerateAuthorizationDocument(
|
|
|
|
|
|
context.Background(),
|
|
|
|
|
|
999, // userID
|
|
|
|
|
|
888, // orderID
|
|
|
|
|
|
777, // queryID
|
|
|
|
|
|
userInfo,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证结果
|
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
assert.NotNil(t, authDoc)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证文件是否真的被创建
|
|
|
|
|
|
if _, err := os.Stat(authDoc.FilePath); err == nil {
|
|
|
|
|
|
t.Logf("✅ PDF文件生成成功!")
|
|
|
|
|
|
t.Logf("📄 文件名: %s", authDoc.FileName)
|
|
|
|
|
|
t.Logf("📁 文件路径: %s", authDoc.FilePath)
|
|
|
|
|
|
t.Logf("🔗 相对路径: %s", authDoc.FileUrl)
|
|
|
|
|
|
t.Logf("📊 文件大小: %d 字节", authDoc.FileSize)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证文件内容
|
|
|
|
|
|
fileInfo, err := os.Stat(authDoc.FilePath)
|
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
|
|
assert.Greater(t, fileInfo.Size(), int64(1000)) // 文件应该大于1KB
|
|
|
|
|
|
|
|
|
|
|
|
// 验证文件名格式
|
|
|
|
|
|
assert.Regexp(t, `^auth_999_888_\d{8}_\d{6}\.pdf$`, authDoc.FileName)
|
|
|
|
|
|
|
|
|
|
|
|
// 验证路径格式
|
|
|
|
|
|
assert.Regexp(t, `^\d{4}/\d{2}/auth_999_888_\d{8}_\d{6}\.pdf$`, authDoc.FileUrl)
|
|
|
|
|
|
|
|
|
|
|
|
t.Logf("🎉 所有验证通过!")
|
|
|
|
|
|
} else {
|
|
|
|
|
|
t.Errorf("❌ PDF文件未创建: %s", authDoc.FilePath)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 验证数据库调用
|
|
|
|
|
|
mockModel.AssertExpectations(t)
|
|
|
|
|
|
}
|