554 lines
14 KiB
Go
554 lines
14 KiB
Go
package usecase
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/entity"
|
|
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/kyc"
|
|
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/repository"
|
|
"code.30cm.net/digimon/app-cloudep-product-service/pkg/domain/usecase"
|
|
mockRepository "code.30cm.net/digimon/app-cloudep-product-service/pkg/mock/repository"
|
|
repo "code.30cm.net/digimon/app-cloudep-product-service/pkg/repository"
|
|
"code.30cm.net/digimon/library-go/errs"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/zeromicro/go-zero/core/logx"
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
"go.uber.org/mock/gomock"
|
|
"google.golang.org/protobuf/proto"
|
|
)
|
|
|
|
func TestKYCUseCase_Create(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
|
|
mockKYCRepo := mockRepository.NewMockKYCRepository(mockCtrl)
|
|
|
|
useCase := MustKYCUseCase(KYCUseCaseParam{
|
|
KYCRepo: mockKYCRepo,
|
|
})
|
|
|
|
ctx := context.Background()
|
|
uid := "test-user"
|
|
|
|
tests := []struct {
|
|
name string
|
|
input *entity.KYC
|
|
mockSetup func()
|
|
expectedError error
|
|
}{
|
|
{
|
|
name: "查不到資料可以建立",
|
|
input: &entity.KYC{
|
|
UID: uid,
|
|
},
|
|
mockSetup: func() {
|
|
mockKYCRepo.EXPECT().FindLatestByUID(ctx, uid).Return(nil, repo.ErrNotFound)
|
|
mockKYCRepo.EXPECT().Create(ctx, gomock.Any()).Return(nil)
|
|
},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "前一筆為 REJECTED 可建立",
|
|
input: &entity.KYC{
|
|
UID: uid,
|
|
},
|
|
mockSetup: func() {
|
|
mockKYCRepo.EXPECT().FindLatestByUID(ctx, uid).Return(&entity.KYC{
|
|
UID: uid,
|
|
Status: kyc.StatusREJECTED,
|
|
}, nil)
|
|
mockKYCRepo.EXPECT().Create(ctx, gomock.Any()).Return(nil)
|
|
},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "已存在未駁回資料,禁止建立",
|
|
input: &entity.KYC{
|
|
UID: uid,
|
|
},
|
|
mockSetup: func() {
|
|
mockKYCRepo.EXPECT().FindLatestByUID(ctx, uid).Return(&entity.KYC{
|
|
UID: uid,
|
|
Status: kyc.StatusPending,
|
|
}, nil)
|
|
},
|
|
expectedError: errs.ForbiddenL(
|
|
logx.WithContext(ctx),
|
|
[]logx.LogField{
|
|
{Key: "param", Value: &entity.KYC{UID: uid}},
|
|
{Key: "func", Value: "KYCRepo.FindLatestByUID"},
|
|
{Key: "reason", Value: "KYC already in progress or approved"},
|
|
},
|
|
"不能重複送出 KYC 資料",
|
|
),
|
|
},
|
|
{
|
|
name: "查詢資料庫錯誤",
|
|
input: &entity.KYC{
|
|
UID: uid,
|
|
},
|
|
mockSetup: func() {
|
|
mockKYCRepo.EXPECT().FindLatestByUID(ctx, uid).Return(nil, errors.New("database error"))
|
|
},
|
|
expectedError: errs.DBErrorL(
|
|
logx.WithContext(ctx),
|
|
[]logx.LogField{
|
|
{Key: "param", Value: &entity.KYC{UID: uid}},
|
|
{Key: "func", Value: "KYCRepo.FindLatestByUID"},
|
|
{Key: "err", Value: "database error"},
|
|
},
|
|
"failed to get latest kyc",
|
|
),
|
|
},
|
|
{
|
|
name: "建立時資料庫錯誤",
|
|
input: &entity.KYC{
|
|
UID: uid,
|
|
},
|
|
mockSetup: func() {
|
|
mockKYCRepo.EXPECT().FindLatestByUID(ctx, uid).Return(nil, repo.ErrNotFound)
|
|
mockKYCRepo.EXPECT().Create(ctx, gomock.Any()).Return(errors.New("insert failed"))
|
|
},
|
|
expectedError: errs.DBErrorL(
|
|
logx.WithContext(ctx),
|
|
[]logx.LogField{
|
|
{Key: "param", Value: &entity.KYC{UID: uid, Status: kyc.StatusPending}},
|
|
{Key: "func", Value: "KYCRepo.Create"},
|
|
{Key: "err", Value: "insert failed"},
|
|
},
|
|
"failed to create kyc review",
|
|
),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
tt.mockSetup()
|
|
|
|
err := useCase.Create(ctx, tt.input)
|
|
|
|
if tt.expectedError == nil {
|
|
assert.NoError(t, err)
|
|
} else {
|
|
assert.Error(t, err)
|
|
assert.Equal(t, tt.expectedError.Error(), err.Error())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestKYCUseCase_FindLatestByUID(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
|
|
mockKYCRepo := mockRepository.NewMockKYCRepository(mockCtrl)
|
|
|
|
useCase := MustKYCUseCase(KYCUseCaseParam{
|
|
KYCRepo: mockKYCRepo,
|
|
})
|
|
|
|
ctx := context.Background()
|
|
uid := "test-user"
|
|
|
|
tests := []struct {
|
|
name string
|
|
inputUID string
|
|
mockSetup func()
|
|
expectedResult *entity.KYC
|
|
expectedError error
|
|
}{
|
|
{
|
|
name: "查詢成功",
|
|
inputUID: uid,
|
|
mockSetup: func() {
|
|
mockKYCRepo.EXPECT().FindLatestByUID(ctx, uid).Return(&entity.KYC{
|
|
UID: uid,
|
|
Status: kyc.StatusPending,
|
|
}, nil)
|
|
},
|
|
expectedResult: &entity.KYC{
|
|
UID: uid,
|
|
Status: kyc.StatusPending,
|
|
},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "資料庫錯誤",
|
|
inputUID: uid,
|
|
mockSetup: func() {
|
|
mockKYCRepo.EXPECT().FindLatestByUID(ctx, uid).Return(nil, errors.New("database error"))
|
|
},
|
|
expectedResult: nil,
|
|
expectedError: errs.DBErrorL(
|
|
logx.WithContext(ctx),
|
|
[]logx.LogField{
|
|
{Key: "uid", Value: uid},
|
|
{Key: "func", Value: "KYCRepo.FindLatestByUID"},
|
|
{Key: "err", Value: "database error"},
|
|
},
|
|
"failed to get latest kyc",
|
|
),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
tt.mockSetup()
|
|
|
|
result, err := useCase.FindLatestByUID(ctx, tt.inputUID)
|
|
|
|
if tt.expectedError == nil {
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tt.expectedResult, result)
|
|
} else {
|
|
assert.Error(t, err)
|
|
assert.Equal(t, tt.expectedError.Error(), err.Error())
|
|
assert.Nil(t, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestKYCUseCase_FindByID(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
|
|
mockKYCRepo := mockRepository.NewMockKYCRepository(mockCtrl)
|
|
|
|
useCase := MustKYCUseCase(KYCUseCaseParam{
|
|
KYCRepo: mockKYCRepo,
|
|
})
|
|
|
|
ctx := context.Background()
|
|
objID := primitive.NewObjectID()
|
|
idStr := objID.Hex()
|
|
|
|
tests := []struct {
|
|
name string
|
|
inputID string
|
|
mockSetup func()
|
|
expectedResult *entity.KYC
|
|
expectedError error
|
|
}{
|
|
{
|
|
name: "查詢成功",
|
|
inputID: idStr,
|
|
mockSetup: func() {
|
|
mockKYCRepo.EXPECT().FindByID(ctx, idStr).Return(&entity.KYC{
|
|
ID: objID,
|
|
UID: "user-1",
|
|
Status: kyc.StatusAPPROVED,
|
|
}, nil)
|
|
},
|
|
expectedResult: &entity.KYC{
|
|
ID: objID,
|
|
UID: "user-1",
|
|
Status: kyc.StatusAPPROVED,
|
|
},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "資料庫錯誤",
|
|
inputID: idStr,
|
|
mockSetup: func() {
|
|
mockKYCRepo.EXPECT().FindByID(ctx, idStr).Return(nil, errors.New("database error"))
|
|
},
|
|
expectedResult: nil,
|
|
expectedError: errs.DBErrorL(
|
|
logx.WithContext(ctx),
|
|
[]logx.LogField{
|
|
{Key: "id", Value: idStr},
|
|
{Key: "func", Value: "KYCRepo.FindByID"},
|
|
{Key: "err", Value: "database error"},
|
|
},
|
|
"failed to get kyc",
|
|
),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
tt.mockSetup()
|
|
|
|
result, err := useCase.FindByID(ctx, tt.inputID)
|
|
|
|
if tt.expectedError == nil {
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, tt.expectedResult, result)
|
|
} else {
|
|
assert.Error(t, err)
|
|
assert.Equal(t, tt.expectedError.Error(), err.Error())
|
|
assert.Nil(t, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestKYCUseCase_List(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
|
|
mockKYCRepo := mockRepository.NewMockKYCRepository(mockCtrl)
|
|
|
|
useCase := MustKYCUseCase(KYCUseCaseParam{
|
|
KYCRepo: mockKYCRepo,
|
|
})
|
|
|
|
ctx := context.Background()
|
|
uid := "user-1"
|
|
country := "TW"
|
|
status := kyc.StatusAPPROVED
|
|
ss := status.ToString()
|
|
|
|
tests := []struct {
|
|
name string
|
|
inputParams usecase.KYCQueryParams
|
|
mockSetup func()
|
|
expectedList []*entity.KYC
|
|
expectedCount int64
|
|
expectedError error
|
|
}{
|
|
{
|
|
name: "查詢成功",
|
|
inputParams: usecase.KYCQueryParams{
|
|
PageIndex: 1,
|
|
PageSize: 10,
|
|
UID: &uid,
|
|
Country: &country,
|
|
Status: &ss,
|
|
},
|
|
mockSetup: func() {
|
|
mockKYCRepo.EXPECT().List(ctx, repository.KYCQueryParams{
|
|
PageIndex: 1,
|
|
PageSize: 10,
|
|
UID: &uid,
|
|
Country: &country,
|
|
Status: &ss,
|
|
SortByDate: true,
|
|
}).Return([]*entity.KYC{
|
|
{UID: uid, CountryRegion: country, Status: status},
|
|
}, int64(1), nil)
|
|
},
|
|
expectedList: []*entity.KYC{
|
|
{UID: uid, CountryRegion: country, Status: status},
|
|
},
|
|
expectedCount: 1,
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "查詢失敗 - 資料庫錯誤",
|
|
inputParams: usecase.KYCQueryParams{
|
|
PageIndex: 2,
|
|
PageSize: 20,
|
|
},
|
|
mockSetup: func() {
|
|
mockKYCRepo.EXPECT().List(ctx, repository.KYCQueryParams{
|
|
PageIndex: 2,
|
|
PageSize: 20,
|
|
SortByDate: true,
|
|
}).Return(nil, int64(0), errors.New("database error"))
|
|
},
|
|
expectedList: nil,
|
|
expectedCount: 0,
|
|
expectedError: errs.DBErrorL(logx.WithContext(ctx),
|
|
[]logx.LogField{
|
|
{Key: "params", Value: usecase.KYCQueryParams{
|
|
PageIndex: 2,
|
|
PageSize: 20,
|
|
}},
|
|
{Key: "func", Value: "KYCRepo.List"},
|
|
{Key: "err", Value: "database error"},
|
|
}, "failed to list kyc"),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
tt.mockSetup()
|
|
|
|
list, count, err := useCase.List(ctx, tt.inputParams)
|
|
|
|
assert.Equal(t, tt.expectedList, list)
|
|
assert.Equal(t, tt.expectedCount, count)
|
|
|
|
if tt.expectedError == nil {
|
|
assert.NoError(t, err)
|
|
} else {
|
|
assert.Error(t, err)
|
|
assert.Equal(t, tt.expectedError.Error(), err.Error())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestKYCUseCase_UpdateStatus(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
|
|
mockKYCRepo := mockRepository.NewMockKYCRepository(mockCtrl)
|
|
|
|
useCase := MustKYCUseCase(KYCUseCaseParam{
|
|
KYCRepo: mockKYCRepo,
|
|
})
|
|
|
|
ctx := context.Background()
|
|
|
|
id := primitive.NewObjectID().Hex()
|
|
status := kyc.StatusAPPROVED
|
|
reason := "all good"
|
|
|
|
tests := []struct {
|
|
name string
|
|
id string
|
|
status kyc.Status
|
|
reason string
|
|
mockSetup func()
|
|
expectedError error
|
|
}{
|
|
{
|
|
name: "更新成功",
|
|
id: id,
|
|
status: status,
|
|
reason: reason,
|
|
mockSetup: func() {
|
|
mockKYCRepo.EXPECT().UpdateStatus(ctx, id, status.ToString(), reason).Return(nil)
|
|
},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "更新失敗 - DB 錯誤",
|
|
id: id,
|
|
status: status,
|
|
reason: reason,
|
|
mockSetup: func() {
|
|
mockKYCRepo.EXPECT().UpdateStatus(ctx, id, status.ToString(), reason).Return(errors.New("db error"))
|
|
},
|
|
expectedError: errs.DBErrorL(
|
|
logx.WithContext(ctx),
|
|
[]logx.LogField{
|
|
{Key: "params", Value: fmt.Sprintf("id:%s, status:%s, reason: %s", id, status, reason)},
|
|
{Key: "func", Value: "KYCRepo.UpdateStatus"},
|
|
{Key: "err", Value: "db error"},
|
|
},
|
|
"failed to update kyc status",
|
|
),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
tt.mockSetup()
|
|
|
|
err := useCase.UpdateStatus(ctx, tt.id, tt.status.ToString(), tt.reason)
|
|
|
|
if tt.expectedError == nil {
|
|
assert.NoError(t, err)
|
|
} else {
|
|
assert.Error(t, err)
|
|
assert.Equal(t, tt.expectedError.Error(), err.Error())
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestKYCUseCase_UpdateKYCInfo(t *testing.T) {
|
|
mockCtrl := gomock.NewController(t)
|
|
defer mockCtrl.Finish()
|
|
|
|
mockKYCRepo := mockRepository.NewMockKYCRepository(mockCtrl)
|
|
|
|
useCase := MustKYCUseCase(KYCUseCaseParam{
|
|
KYCRepo: mockKYCRepo,
|
|
})
|
|
|
|
ctx := context.Background()
|
|
id := primitive.NewObjectID().Hex()
|
|
|
|
updateParams := &usecase.KYCUpdateParams{
|
|
Name: proto.String("Daniel Wang"),
|
|
Identification: proto.String("A123456789"),
|
|
IdentificationType: proto.String("passport"),
|
|
Address: proto.String("Taipei City"),
|
|
PostalCode: proto.String("100"),
|
|
DateOfBirth: proto.String("1993-04-17"),
|
|
Gender: proto.String("M"),
|
|
IDFrontImage: proto.String("https://example.com/front.jpg"),
|
|
IDBackImage: proto.String("https://example.com/back.jpg"),
|
|
BankStatementImg: proto.String("https://example.com/bank.jpg"),
|
|
BankCode: proto.String("123"),
|
|
BankName: proto.String("ABC Bank"),
|
|
BranchCode: proto.String("001"),
|
|
BranchName: proto.String("Taipei Branch"),
|
|
BankAccount: proto.String("1234567890"),
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
id string
|
|
input *usecase.KYCUpdateParams
|
|
mockSetup func()
|
|
expectedError error
|
|
}{
|
|
{
|
|
name: "更新成功",
|
|
id: id,
|
|
input: updateParams,
|
|
mockSetup: func() {
|
|
mockKYCRepo.EXPECT().UpdateKYCInfo(ctx, id, &repository.KYCUpdateParams{
|
|
Name: updateParams.Name,
|
|
Identification: updateParams.Identification,
|
|
IdentificationType: updateParams.IdentificationType,
|
|
Address: updateParams.Address,
|
|
PostalCode: updateParams.PostalCode,
|
|
DateOfBirth: updateParams.DateOfBirth,
|
|
Gender: updateParams.Gender,
|
|
IDFrontImage: updateParams.IDFrontImage,
|
|
IDBackImage: updateParams.IDBackImage,
|
|
BankStatementImg: updateParams.BankStatementImg,
|
|
BankCode: updateParams.BankCode,
|
|
BankName: updateParams.BankName,
|
|
BranchCode: updateParams.BranchCode,
|
|
BranchName: updateParams.BranchName,
|
|
BankAccount: updateParams.BankAccount,
|
|
}).Return(nil)
|
|
},
|
|
expectedError: nil,
|
|
},
|
|
{
|
|
name: "更新失敗 - DB 錯誤",
|
|
id: id,
|
|
input: updateParams,
|
|
mockSetup: func() {
|
|
mockKYCRepo.EXPECT().UpdateKYCInfo(ctx, id, gomock.Any()).Return(errors.New("db error"))
|
|
},
|
|
expectedError: errs.DBErrorL(logx.WithContext(ctx),
|
|
[]logx.LogField{
|
|
{Key: "id", Value: id},
|
|
{Key: "params", Value: updateParams},
|
|
{Key: "func", Value: "KYCRepo.UpdateKYCInfo"},
|
|
{Key: "err", Value: "db error"},
|
|
},
|
|
"failed to update kyc",
|
|
),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
tt.mockSetup()
|
|
|
|
err := useCase.UpdateKYCInfo(ctx, tt.id, tt.input)
|
|
|
|
if tt.expectedError == nil {
|
|
assert.NoError(t, err)
|
|
} else {
|
|
assert.Error(t, err)
|
|
assert.Equal(t, tt.expectedError.Error(), err.Error())
|
|
}
|
|
})
|
|
}
|
|
}
|