113 lines
4.2 KiB
Go
113 lines
4.2 KiB
Go
package business
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"testing"
|
|
)
|
|
|
|
type bindingRepoFake struct {
|
|
BindingRepo
|
|
mu sync.Mutex
|
|
rows []*Binding
|
|
saved *Binding
|
|
scope UserScope
|
|
filter BindingFilter
|
|
}
|
|
|
|
func (r *bindingRepoFake) WithPlatformLock(ctx context.Context, _ PlatformKey, fn func(context.Context) error) error {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
return fn(ctx)
|
|
}
|
|
func (r *bindingRepoFake) ForPlatform(context.Context, PlatformKey) ([]*Binding, error) {
|
|
return r.rows, nil
|
|
}
|
|
func (r *bindingRepoFake) Save(_ context.Context, b *Binding) error {
|
|
r.saved = b
|
|
r.rows = []*Binding{b}
|
|
return nil
|
|
}
|
|
func (r *bindingRepoFake) List(_ context.Context, s UserScope, q BindingFilter, _ ...ListOption) ([]*Binding, int64, error) {
|
|
r.scope, r.filter = s, q
|
|
return []*Binding{}, 0, nil
|
|
}
|
|
|
|
type platformRepoFake struct {
|
|
account *PlatformAccount
|
|
calls int
|
|
}
|
|
|
|
func (r *platformRepoFake) FindByAccount(context.Context, string, string) (*PlatformAccount, error) {
|
|
r.calls++
|
|
return r.account, nil
|
|
}
|
|
|
|
type passwordFake struct{}
|
|
|
|
func (passwordFake) Verify(string, string) (bool, error) { return true, nil }
|
|
|
|
func newBindingTestUsecase(repo *bindingRepoFake) (*BindingUsecase, *platformRepoFake) {
|
|
a := &accountRepoFake{accounts: map[uint]*Account{1: {ID: 1, Level: 1, IDPath: "0"}, 2: {ID: 2, Level: 2, IDPath: "0,1", ParentID: 1}, 3: {ID: 3, Level: 3, IDPath: "0,1,2", ParentID: 2}, 4: {ID: 4, Level: 3, IDPath: "0,1,2", ParentID: 2}}}
|
|
p := &platformRepoFake{account: &PlatformAccount{ID: 7, Status: 1}}
|
|
return NewBindingUsecase(repo, NewAccountUsecase(a), p, passwordFake{}), p
|
|
}
|
|
|
|
func TestBindingTransitionsAndLevel(t *testing.T) {
|
|
for _, item := range []struct {
|
|
name string
|
|
existing *Binding
|
|
want error
|
|
}{
|
|
{"新增", nil, nil}, {"重提驳回", &Binding{UserID: 3, Status: "2"}, nil}, {"本人通过", &Binding{UserID: 3, Status: "0"}, ErrBindingExists},
|
|
{"本人待审核", &Binding{UserID: 3, Status: "3"}, ErrBindingPending}, {"其他账号通过", &Binding{UserID: 4, Status: "0"}, ErrBindingOccupied}, {"其他账号待审核", &Binding{UserID: 4, Status: "3"}, ErrBindingOccupied},
|
|
} {
|
|
t.Run(item.name, func(t *testing.T) {
|
|
r := &bindingRepoFake{}
|
|
if item.existing != nil {
|
|
r.rows = []*Binding{item.existing}
|
|
}
|
|
uc, _ := newBindingTestUsecase(r)
|
|
if err := uc.Bind(accountContext(3, 903), "LX", " sdk ", "password"); err != item.want {
|
|
t.Fatalf("绑定结果错误: %v", err)
|
|
}
|
|
if item.want == nil && (r.saved.Status != "3" || r.saved.Account != "sdk" || r.saved.SourceDB != "lx" || r.saved.RejectReason != nil || r.saved.ReviewTime != nil || r.saved.ReviewAccount != nil) {
|
|
t.Fatalf("待审核状态未正确重置: %+v", r.saved)
|
|
}
|
|
})
|
|
}
|
|
r := &bindingRepoFake{}
|
|
uc, p := newBindingTestUsecase(r)
|
|
if err := uc.Bind(accountContext(2, 902), "lx", "sdk", "password"); err != ErrBindingLevel || p.calls != 0 {
|
|
t.Fatal("非三级不应访问平台验密")
|
|
}
|
|
}
|
|
|
|
func TestBindingScopesMatchBusinessLevels(t *testing.T) {
|
|
r := &bindingRepoFake{}
|
|
uc, _ := newBindingTestUsecase(r)
|
|
if _, _, err := uc.List(accountContext(1, 901), BindingFilter{}); err != nil || r.scope.IncludeSelf || r.scope.OnlySelf || r.scope.DescendantPath != "0,1" {
|
|
t.Fatalf("一级仅查看下级绑定: %+v %v", r.scope, err)
|
|
}
|
|
if _, _, err := uc.List(accountContext(3, 903), BindingFilter{}); err != nil || !r.scope.OnlySelf || r.scope.SelfID != 3 {
|
|
t.Fatal("三级只能查看自己的绑定")
|
|
}
|
|
if _, err := uc.ForUser(accountContext(1, 901), 3); err != nil || r.filter.Status != "0" || r.filter.UserID != 3 {
|
|
t.Fatal("绑定详情必须仅已通过")
|
|
}
|
|
}
|
|
|
|
func TestBindingConcurrentSubmissionHasOneOwner(t *testing.T) {
|
|
r := &bindingRepoFake{}
|
|
uc, _ := newBindingTestUsecase(r)
|
|
// 每个用例独立的平台桩避免把桩的计数器带进并发断言。
|
|
other, _ := newBindingTestUsecase(r)
|
|
errors := make(chan error, 2)
|
|
go func() { errors <- uc.Bind(accountContext(3, 903), "lx", "sdk", "password") }()
|
|
go func() { errors <- other.Bind(accountContext(4, 903), "lx", "sdk", "password") }()
|
|
first, second := <-errors, <-errors
|
|
if !((first == nil && second == ErrBindingOccupied) || (second == nil && first == ErrBindingOccupied)) {
|
|
t.Fatalf("同一平台商务必须独占: %v %v", first, second)
|
|
}
|
|
}
|