🔥A cross-language distributed transaction manager. Support xa, tcc, saga, transactional messages. 跨语言分布式事务管理器
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

201 lines
6.1 KiB

package test
import (
"fmt"
"testing"
"time"
"github.com/dtm-labs/dtm/client/dtmcli/dtmimp"
"github.com/dtm-labs/dtm/dtmsvr/storage"
"github.com/dtm-labs/dtm/dtmsvr/storage/registry"
"github.com/dtm-labs/dtm/dtmutil"
"github.com/stretchr/testify/assert"
)
func initTransGlobal(gid string) (*storage.TransGlobalStore, storage.Store) {
next := time.Now().Add(10 * time.Second)
return initTransGlobalByNextCronTime(gid, next)
}
func initTransGlobalByNextCronTime(gid string, next time.Time) (*storage.TransGlobalStore, storage.Store) {
g := &storage.TransGlobalStore{Gid: gid, Status: "prepared", NextCronTime: &next}
bs := []storage.TransBranchStore{
{Gid: gid, BranchID: "01"},
}
s := registry.GetStore()
err := s.MaySaveNewTrans(g, bs)
dtmimp.E2P(err)
return g, s
}
func TestStoreSave(t *testing.T) {
gid := dtmimp.GetFuncName()
bs := []storage.TransBranchStore{
{Gid: gid, BranchID: "01"},
{Gid: gid, BranchID: "02"},
}
g, s := initTransGlobal(gid)
g2 := s.FindTransGlobalStore(gid)
assert.NotNil(t, g2)
assert.Equal(t, gid, g2.Gid)
bs2 := s.FindBranches(gid)
assert.Equal(t, len(bs2), int(1))
assert.Equal(t, "01", bs2[0].BranchID)
s.LockGlobalSaveBranches(gid, g.Status, []storage.TransBranchStore{bs[1]}, -1)
bs3 := s.FindBranches(gid)
assert.Equal(t, 2, len(bs3))
assert.Equal(t, "02", bs3[1].BranchID)
assert.Equal(t, "01", bs3[0].BranchID)
err := dtmimp.CatchP(func() {
s.LockGlobalSaveBranches(g.Gid, "submitted", []storage.TransBranchStore{bs[1]}, 1)
})
assert.Equal(t, storage.ErrNotFound, err)
s.ChangeGlobalStatus(g, "succeed", []string{}, true)
}
func TestStoreChangeStatus(t *testing.T) {
gid := dtmimp.GetFuncName()
g, s := initTransGlobal(gid)
g.Status = "no"
err := dtmimp.CatchP(func() {
s.ChangeGlobalStatus(g, "submitted", []string{}, false)
})
assert.Equal(t, storage.ErrNotFound, err)
g.Status = "prepared"
s.ChangeGlobalStatus(g, "submitted", []string{}, false)
s.ChangeGlobalStatus(g, "succeed", []string{}, true)
}
func TestStoreLockTrans(t *testing.T) {
// lock trans will only lock unfinished trans. ensure all other trans are finished
gid := dtmimp.GetFuncName()
g, s := initTransGlobal(gid)
g2 := s.LockOneGlobalTrans(2 * time.Duration(conf.RetryInterval) * time.Second)
assert.NotNil(t, g2)
assert.Equal(t, gid, g2.Gid)
s.TouchCronTime(g, 3*conf.RetryInterval, dtmutil.GetNextTime(3*conf.RetryInterval))
g2 = s.LockOneGlobalTrans(2 * time.Duration(conf.RetryInterval) * time.Second)
assert.Nil(t, g2)
s.TouchCronTime(g, 1*conf.RetryInterval, dtmutil.GetNextTime(1*conf.RetryInterval))
g2 = s.LockOneGlobalTrans(2 * time.Duration(conf.RetryInterval) * time.Second)
assert.NotNil(t, g2)
assert.Equal(t, gid, g2.Gid)
s.ChangeGlobalStatus(g, "succeed", []string{}, true)
g2 = s.LockOneGlobalTrans(2 * time.Duration(conf.RetryInterval) * time.Second)
assert.Nil(t, g2)
}
func TestStoreResetCronTime(t *testing.T) {
s := registry.GetStore()
testStoreResetCronTime(t, dtmimp.GetFuncName(), func(timeout int64, limit int64) (int64, bool, error) {
return s.ResetCronTime(time.Duration(timeout)*time.Second, limit)
})
}
func testStoreResetCronTime(t *testing.T, funcName string, resetCronHandler func(expire int64, limit int64) (int64, bool, error)) {
s := registry.GetStore()
var afterSeconds, lockExpireIn, limit, i int64
afterSeconds = 100
lockExpireIn = 2
limit = 10
// Will be reset
for i = 0; i < limit; i++ {
gid := funcName + fmt.Sprintf("%d", i)
_, _ = initTransGlobalByNextCronTime(gid, time.Now().Add(time.Duration(afterSeconds+10)*time.Second))
}
// Will not be reset
gid := funcName + fmt.Sprintf("%d", 10)
_, _ = initTransGlobalByNextCronTime(gid, time.Now().Add(time.Duration(afterSeconds-10)*time.Second))
// Not Found
g := s.LockOneGlobalTrans(time.Duration(lockExpireIn) * time.Second)
assert.Nil(t, g)
// Reset limit-1 count
succeedCount, hasRemaining, err := resetCronHandler(afterSeconds, limit-1)
assert.Equal(t, hasRemaining, true)
assert.Equal(t, succeedCount, limit-1)
assert.Nil(t, err)
// Found limit-1 count
for i = 0; i < limit-1; i++ {
g = s.LockOneGlobalTrans(time.Duration(lockExpireIn) * time.Second)
assert.NotNil(t, g)
s.ChangeGlobalStatus(g, "succeed", []string{}, true)
}
// Not Found
g = s.LockOneGlobalTrans(time.Duration(lockExpireIn) * time.Second)
assert.Nil(t, g)
// Reset 1 count
succeedCount, hasRemaining, err = resetCronHandler(afterSeconds, limit)
assert.Equal(t, hasRemaining, false)
assert.Equal(t, succeedCount, int64(1))
assert.Nil(t, err)
// Found 1 count
g = s.LockOneGlobalTrans(time.Duration(lockExpireIn) * time.Second)
assert.NotNil(t, g)
s.ChangeGlobalStatus(g, "succeed", []string{}, true)
// Not Found
g = s.LockOneGlobalTrans(time.Duration(lockExpireIn) * time.Second)
assert.Nil(t, g)
// reduce the resetTimeTimeout, Reset 1 count
succeedCount, hasRemaining, err = resetCronHandler(afterSeconds-12, limit)
assert.Equal(t, hasRemaining, false)
assert.Equal(t, succeedCount, int64(1))
assert.Nil(t, err)
// Found 1 count
g = s.LockOneGlobalTrans(time.Duration(lockExpireIn) * time.Second)
assert.NotNil(t, g)
s.ChangeGlobalStatus(g, "succeed", []string{}, true)
// Not Found
g = s.LockOneGlobalTrans(time.Duration(lockExpireIn) * time.Second)
assert.Nil(t, g)
// Not Found
succeedCount, hasRemaining, err = resetCronHandler(afterSeconds-12, limit)
assert.Equal(t, hasRemaining, false)
assert.Equal(t, succeedCount, int64(0))
assert.Nil(t, err)
}
func TestUpdateBranches(t *testing.T) {
if !conf.Store.IsDB() {
_, err := registry.GetStore().UpdateBranches(nil, nil)
assert.Nil(t, err)
}
}
func TestResetTransGlobalCronTime(t *testing.T) {
gid := dtmimp.GetFuncName()
g, _ := initTransGlobal(gid)
s := registry.GetStore()
g2 := s.FindTransGlobalStore(gid)
assert.NotNil(t, g2)
assert.Equal(t, gid, g2.Gid)
s.ResetTransGlobalCronTime(g2)
g2 = s.FindTransGlobalStore(gid)
assert.NotNil(t, g2)
assert.Equal(t, gid, g2.Gid)
assert.Greater(t, time.Now().Add(3*time.Second), *g2.NextCronTime)
assert.Equal(t, g2.UpdateTime, g2.NextCronTime)
assert.NotEqual(t, g.UpdateTime, g2.UpdateTime)
assert.NotEqual(t, g.NextCronTime, g2.NextCronTime)
s.ChangeGlobalStatus(g, "succeed", []string{}, true)
}