split the big test file
This commit is contained in:
parent
0a653d0972
commit
3aa70932d3
@ -7,6 +7,7 @@ branches:
|
|||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
- main
|
- main
|
||||||
|
- test
|
||||||
services:
|
services:
|
||||||
- mysql
|
- mysql
|
||||||
before_install:
|
before_install:
|
||||||
|
|||||||
@ -3,9 +3,7 @@ package dtmsvr
|
|||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
@ -19,7 +17,7 @@ var DtmServer = examples.DtmServer
|
|||||||
var Busi = examples.Busi
|
var Busi = examples.Busi
|
||||||
var app *gin.Engine
|
var app *gin.Engine
|
||||||
|
|
||||||
func init() {
|
func TestMain(m *testing.M) {
|
||||||
TransProcessedTestChan = make(chan string, 1)
|
TransProcessedTestChan = make(chan string, 1)
|
||||||
common.InitApp(common.GetProjectDir(), &config)
|
common.InitApp(common.GetProjectDir(), &config)
|
||||||
config.Mysql["database"] = dbName
|
config.Mysql["database"] = dbName
|
||||||
@ -40,34 +38,7 @@ func init() {
|
|||||||
e2p(dbGet().Exec("truncate trans_branch").Error)
|
e2p(dbGet().Exec("truncate trans_branch").Error)
|
||||||
e2p(dbGet().Exec("truncate trans_log").Error)
|
e2p(dbGet().Exec("truncate trans_log").Error)
|
||||||
examples.ResetXaData()
|
examples.ResetXaData()
|
||||||
}
|
m.Run()
|
||||||
|
|
||||||
func TestDtmSvr(t *testing.T) {
|
|
||||||
|
|
||||||
tccBarrierDisorder(t)
|
|
||||||
tccBarrierNormal(t)
|
|
||||||
tccBarrierRollback(t)
|
|
||||||
sagaBarrierNormal(t)
|
|
||||||
sagaBarrierRollback(t)
|
|
||||||
msgNormal(t)
|
|
||||||
msgPending(t)
|
|
||||||
tccNormal(t)
|
|
||||||
tccRollback(t)
|
|
||||||
sagaNormal(t)
|
|
||||||
xaNormal(t)
|
|
||||||
xaRollback(t)
|
|
||||||
sagaCommittedPending(t)
|
|
||||||
sagaRollback(t)
|
|
||||||
|
|
||||||
// for coverage
|
|
||||||
examples.QsStartSvr()
|
|
||||||
assertSucceed(t, examples.QsFireRequest())
|
|
||||||
assertSucceed(t, examples.MsgFireRequest())
|
|
||||||
assertSucceed(t, examples.SagaBarrierFireRequest())
|
|
||||||
assertSucceed(t, examples.SagaFireRequest())
|
|
||||||
assertSucceed(t, examples.TccBarrierFireRequest())
|
|
||||||
assertSucceed(t, examples.TccFireRequest())
|
|
||||||
assertSucceed(t, examples.XaFireRequest())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCover(t *testing.T) {
|
func TestCover(t *testing.T) {
|
||||||
@ -98,177 +69,6 @@ func getBranchesStatus(gid string) []string {
|
|||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
|
|
||||||
func xaNormal(t *testing.T) {
|
|
||||||
xc := examples.XaClient
|
|
||||||
gid, err := xc.XaGlobalTransaction(func(xa *dtmcli.Xa) error {
|
|
||||||
req := examples.GenTransReq(30, false, false)
|
|
||||||
resp, err := xa.CallBranch(req, examples.Busi+"/TransOutXa")
|
|
||||||
common.CheckRestySuccess(resp, err)
|
|
||||||
resp, err = xa.CallBranch(req, examples.Busi+"/TransInXa")
|
|
||||||
common.CheckRestySuccess(resp, err)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
e2p(err)
|
|
||||||
WaitTransProcessed(gid)
|
|
||||||
assert.Equal(t, []string{"prepared", "succeed", "prepared", "succeed"}, getBranchesStatus(gid))
|
|
||||||
}
|
|
||||||
|
|
||||||
func xaRollback(t *testing.T) {
|
|
||||||
xc := examples.XaClient
|
|
||||||
gid, err := xc.XaGlobalTransaction(func(xa *dtmcli.Xa) error {
|
|
||||||
req := examples.GenTransReq(30, false, true)
|
|
||||||
resp, err := xa.CallBranch(req, examples.Busi+"/TransOutXa")
|
|
||||||
common.CheckRestySuccess(resp, err)
|
|
||||||
resp, err = xa.CallBranch(req, examples.Busi+"/TransInXa")
|
|
||||||
common.CheckRestySuccess(resp, err)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
logrus.Errorf("global transaction failed, so rollback")
|
|
||||||
}
|
|
||||||
WaitTransProcessed(gid)
|
|
||||||
assert.Equal(t, []string{"succeed", "prepared"}, getBranchesStatus(gid))
|
|
||||||
assert.Equal(t, "failed", getTransStatus(gid))
|
|
||||||
}
|
|
||||||
|
|
||||||
func tccNormal(t *testing.T) {
|
|
||||||
data := &examples.TransReq{Amount: 30}
|
|
||||||
_, err := dtmcli.TccGlobalTransaction(examples.DtmServer, func(tcc *dtmcli.Tcc) (rerr error) {
|
|
||||||
_, rerr = tcc.CallBranch(data, Busi+"/TransOut", Busi+"/TransOutConfirm", Busi+"/TransOutRevert")
|
|
||||||
e2p(rerr)
|
|
||||||
_, rerr = tcc.CallBranch(data, Busi+"/TransIn", Busi+"/TransInConfirm", Busi+"/TransInRevert")
|
|
||||||
e2p(rerr)
|
|
||||||
return
|
|
||||||
})
|
|
||||||
e2p(err)
|
|
||||||
}
|
|
||||||
func tccBarrierNormal(t *testing.T) {
|
|
||||||
_, err := dtmcli.TccGlobalTransaction(DtmServer, func(tcc *dtmcli.Tcc) (rerr error) {
|
|
||||||
res1, rerr := tcc.CallBranch(&examples.TransReq{Amount: 30}, Busi+"/TccBTransOutTry", Busi+"/TccBTransOutConfirm", Busi+"/TccBTransOutCancel")
|
|
||||||
e2p(rerr)
|
|
||||||
if res1.StatusCode() != 200 {
|
|
||||||
return fmt.Errorf("bad status code: %d", res1.StatusCode())
|
|
||||||
}
|
|
||||||
res2, rerr := tcc.CallBranch(&examples.TransReq{Amount: 30}, Busi+"/TccBTransInTry", Busi+"/TccBTransInConfirm", Busi+"/TccBTransInCancel")
|
|
||||||
e2p(rerr)
|
|
||||||
if res2.StatusCode() != 200 {
|
|
||||||
return fmt.Errorf("bad status code: %d", res2.StatusCode())
|
|
||||||
}
|
|
||||||
logrus.Printf("tcc returns: %s, %s", res1.String(), res2.String())
|
|
||||||
return
|
|
||||||
})
|
|
||||||
e2p(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func tccBarrierRollback(t *testing.T) {
|
|
||||||
gid, err := dtmcli.TccGlobalTransaction(DtmServer, func(tcc *dtmcli.Tcc) (rerr error) {
|
|
||||||
res1, rerr := tcc.CallBranch(&examples.TransReq{Amount: 30}, Busi+"/TccBTransOutTry", Busi+"/TccBTransOutConfirm", Busi+"/TccBTransOutCancel")
|
|
||||||
e2p(rerr)
|
|
||||||
if res1.StatusCode() != 200 {
|
|
||||||
return fmt.Errorf("bad status code: %d", res1.StatusCode())
|
|
||||||
}
|
|
||||||
res2, rerr := tcc.CallBranch(&examples.TransReq{Amount: 30, TransInResult: "FAILURE"}, Busi+"/TccBTransInTry", Busi+"/TccBTransInConfirm", Busi+"/TccBTransInCancel")
|
|
||||||
e2p(rerr)
|
|
||||||
if res2.StatusCode() != 200 {
|
|
||||||
return fmt.Errorf("bad status code: %d", res2.StatusCode())
|
|
||||||
}
|
|
||||||
if strings.Contains(res2.String(), "FAILURE") {
|
|
||||||
return fmt.Errorf("branch trans in fail")
|
|
||||||
}
|
|
||||||
logrus.Printf("tcc returns: %s, %s", res1.String(), res2.String())
|
|
||||||
return
|
|
||||||
})
|
|
||||||
assert.Equal(t, err, fmt.Errorf("branch trans in fail"))
|
|
||||||
WaitTransProcessed(gid)
|
|
||||||
assert.Equal(t, "failed", getTransStatus(gid))
|
|
||||||
}
|
|
||||||
|
|
||||||
func tccRollback(t *testing.T) {
|
|
||||||
data := &examples.TransReq{Amount: 30, TransInResult: "FAILURE"}
|
|
||||||
_, err := dtmcli.TccGlobalTransaction(examples.DtmServer, func(tcc *dtmcli.Tcc) (rerr error) {
|
|
||||||
_, rerr = tcc.CallBranch(data, Busi+"/TransOut", Busi+"/TransOutConfirm", Busi+"/TransOutRevert")
|
|
||||||
e2p(rerr)
|
|
||||||
_, rerr = tcc.CallBranch(data, Busi+"/TransIn", Busi+"/TransInConfirm", Busi+"/TransInRevert")
|
|
||||||
e2p(rerr)
|
|
||||||
return
|
|
||||||
})
|
|
||||||
e2p(err)
|
|
||||||
}
|
|
||||||
func msgNormal(t *testing.T) {
|
|
||||||
msg := genMsg("gid-msg-normal")
|
|
||||||
msg.Submit()
|
|
||||||
assert.Equal(t, "submitted", getTransStatus(msg.Gid))
|
|
||||||
WaitTransProcessed(msg.Gid)
|
|
||||||
assert.Equal(t, []string{"succeed", "succeed"}, getBranchesStatus(msg.Gid))
|
|
||||||
assert.Equal(t, "succeed", getTransStatus(msg.Gid))
|
|
||||||
}
|
|
||||||
|
|
||||||
func msgPending(t *testing.T) {
|
|
||||||
msg := genMsg("gid-msg-normal-pending")
|
|
||||||
msg.Prepare("")
|
|
||||||
assert.Equal(t, "prepared", getTransStatus(msg.Gid))
|
|
||||||
examples.MainSwitch.CanSubmitResult.SetOnce("PENDING")
|
|
||||||
CronTransOnce(60 * time.Second)
|
|
||||||
assert.Equal(t, "prepared", getTransStatus(msg.Gid))
|
|
||||||
examples.MainSwitch.TransInResult.SetOnce("PENDING")
|
|
||||||
CronTransOnce(60 * time.Second)
|
|
||||||
assert.Equal(t, "submitted", getTransStatus(msg.Gid))
|
|
||||||
CronTransOnce(60 * time.Second)
|
|
||||||
assert.Equal(t, []string{"succeed", "succeed"}, getBranchesStatus(msg.Gid))
|
|
||||||
assert.Equal(t, "succeed", getTransStatus(msg.Gid))
|
|
||||||
}
|
|
||||||
|
|
||||||
func sagaNormal(t *testing.T) {
|
|
||||||
saga := genSaga("gid-noramlSaga", false, false)
|
|
||||||
saga.Submit()
|
|
||||||
WaitTransProcessed(saga.Gid)
|
|
||||||
assert.Equal(t, []string{"prepared", "succeed", "prepared", "succeed"}, getBranchesStatus(saga.Gid))
|
|
||||||
assert.Equal(t, "succeed", getTransStatus(saga.Gid))
|
|
||||||
transQuery(t, saga.Gid)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sagaBarrierNormal(t *testing.T) {
|
|
||||||
req := &examples.TransReq{Amount: 30}
|
|
||||||
saga := dtmcli.NewSaga(DtmServer).
|
|
||||||
Add(Busi+"/SagaBTransOut", Busi+"/SagaBTransOutCompensate", req).
|
|
||||||
Add(Busi+"/SagaBTransIn", Busi+"/SagaBTransInCompensate", req)
|
|
||||||
logrus.Printf("busi trans submit")
|
|
||||||
err := saga.Submit()
|
|
||||||
e2p(err)
|
|
||||||
WaitTransProcessed(saga.Gid)
|
|
||||||
assert.Equal(t, []string{"prepared", "succeed", "prepared", "succeed"}, getBranchesStatus(saga.Gid))
|
|
||||||
}
|
|
||||||
|
|
||||||
func sagaRollback(t *testing.T) {
|
|
||||||
saga := genSaga("gid-rollbackSaga2", false, true)
|
|
||||||
saga.Submit()
|
|
||||||
WaitTransProcessed(saga.Gid)
|
|
||||||
assert.Equal(t, "failed", getTransStatus(saga.Gid))
|
|
||||||
assert.Equal(t, []string{"succeed", "succeed", "succeed", "failed"}, getBranchesStatus(saga.Gid))
|
|
||||||
}
|
|
||||||
|
|
||||||
func sagaBarrierRollback(t *testing.T) {
|
|
||||||
saga := dtmcli.NewSaga(DtmServer).
|
|
||||||
Add(Busi+"/SagaBTransOut", Busi+"/SagaBTransOutCompensate", &examples.TransReq{Amount: 30}).
|
|
||||||
Add(Busi+"/SagaBTransIn", Busi+"/SagaBTransInCompensate", &examples.TransReq{Amount: 30, TransInResult: "FAILURE"})
|
|
||||||
logrus.Printf("busi trans submit")
|
|
||||||
err := saga.Submit()
|
|
||||||
e2p(err)
|
|
||||||
WaitTransProcessed(saga.Gid)
|
|
||||||
assert.Equal(t, "failed", getTransStatus(saga.Gid))
|
|
||||||
}
|
|
||||||
|
|
||||||
func sagaCommittedPending(t *testing.T) {
|
|
||||||
saga := genSaga("gid-committedPending", false, false)
|
|
||||||
examples.MainSwitch.TransInResult.SetOnce("PENDING")
|
|
||||||
saga.Submit()
|
|
||||||
WaitTransProcessed(saga.Gid)
|
|
||||||
assert.Equal(t, []string{"prepared", "prepared", "prepared", "prepared"}, getBranchesStatus(saga.Gid))
|
|
||||||
CronTransOnce(60 * time.Second)
|
|
||||||
assert.Equal(t, []string{"prepared", "succeed", "prepared", "succeed"}, getBranchesStatus(saga.Gid))
|
|
||||||
assert.Equal(t, "succeed", getTransStatus(saga.Gid))
|
|
||||||
}
|
|
||||||
|
|
||||||
func assertSucceed(t *testing.T, gid string) {
|
func assertSucceed(t *testing.T, gid string) {
|
||||||
WaitTransProcessed(gid)
|
WaitTransProcessed(gid)
|
||||||
assert.Equal(t, "succeed", getTransStatus(gid))
|
assert.Equal(t, "succeed", getTransStatus(gid))
|
||||||
@ -343,72 +143,3 @@ func TestSqlDB(t *testing.T) {
|
|||||||
dbr = db.Model(&dtmcli.BarrierModel{}).Where("gid=?", "gid2").Find(&[]dtmcli.BarrierModel{})
|
dbr = db.Model(&dtmcli.BarrierModel{}).Where("gid=?", "gid2").Find(&[]dtmcli.BarrierModel{})
|
||||||
asserts.Equal(dbr.RowsAffected, int64(1))
|
asserts.Equal(dbr.RowsAffected, int64(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
func tccBarrierDisorder(t *testing.T) {
|
|
||||||
timeoutChan := make(chan string, 2)
|
|
||||||
finishedChan := make(chan string, 2)
|
|
||||||
gid, err := dtmcli.TccGlobalTransaction(DtmServer, func(tcc *dtmcli.Tcc) (rerr error) {
|
|
||||||
body := &examples.TransReq{Amount: 30}
|
|
||||||
tryURL := Busi + "/TccBTransOutTry"
|
|
||||||
confirmURL := Busi + "/TccBTransOutConfirm"
|
|
||||||
cancelURL := Busi + "/TccBSleepCancel"
|
|
||||||
// 请参见子事务屏障里的时序图,这里为了模拟该时序图,手动拆解了callbranch
|
|
||||||
branchID := tcc.NewBranchID()
|
|
||||||
sleeped := false
|
|
||||||
app.POST(examples.BusiAPI+"/TccBSleepCancel", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
|
|
||||||
res, err := examples.TccBarrierTransOutCancel(c)
|
|
||||||
if !sleeped {
|
|
||||||
sleeped = true
|
|
||||||
logrus.Printf("sleep before cancel return")
|
|
||||||
<-timeoutChan
|
|
||||||
finishedChan <- "1"
|
|
||||||
}
|
|
||||||
return res, err
|
|
||||||
}))
|
|
||||||
// 注册子事务
|
|
||||||
r, err := common.RestyClient.R().
|
|
||||||
SetBody(&M{
|
|
||||||
"gid": tcc.Gid,
|
|
||||||
"branch_id": branchID,
|
|
||||||
"trans_type": "tcc",
|
|
||||||
"status": "prepared",
|
|
||||||
"data": string(common.MustMarshal(body)),
|
|
||||||
"try": tryURL,
|
|
||||||
"confirm": confirmURL,
|
|
||||||
"cancel": cancelURL,
|
|
||||||
}).
|
|
||||||
Post(tcc.Dtm + "/registerTccBranch")
|
|
||||||
e2p(err)
|
|
||||||
assert.True(t, strings.Contains(r.String(), "SUCCESS"))
|
|
||||||
go func() {
|
|
||||||
logrus.Printf("sleeping to wait for tcc try timeout")
|
|
||||||
<-timeoutChan
|
|
||||||
r, _ = common.RestyClient.R().
|
|
||||||
SetBody(body).
|
|
||||||
SetQueryParams(common.MS{
|
|
||||||
"dtm": tcc.Dtm,
|
|
||||||
"gid": tcc.Gid,
|
|
||||||
"branch_id": branchID,
|
|
||||||
"trans_type": "tcc",
|
|
||||||
"branch_type": "try",
|
|
||||||
}).
|
|
||||||
Post(tryURL)
|
|
||||||
assert.True(t, strings.Contains(r.String(), "FAILURE"))
|
|
||||||
finishedChan <- "1"
|
|
||||||
}()
|
|
||||||
logrus.Printf("cron to timeout and then call cancel")
|
|
||||||
go CronTransOnce(60 * time.Second)
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
logrus.Printf("cron to timeout and then call cancelled twice")
|
|
||||||
CronTransOnce(60 * time.Second)
|
|
||||||
timeoutChan <- "wake"
|
|
||||||
timeoutChan <- "wake"
|
|
||||||
<-finishedChan
|
|
||||||
<-finishedChan
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
return fmt.Errorf("a cancelled tcc")
|
|
||||||
})
|
|
||||||
assert.Error(t, err, fmt.Errorf("a cancelled tcc"))
|
|
||||||
assert.Equal(t, []string{"succeed", "prepared", "prepared"}, getBranchesStatus(gid))
|
|
||||||
assert.Equal(t, "failed", getTransStatus(gid))
|
|
||||||
}
|
|
||||||
|
|||||||
19
dtmsvr/examples_test.go
Normal file
19
dtmsvr/examples_test.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package dtmsvr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/yedf/dtm/examples"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestExamples(t *testing.T) {
|
||||||
|
// for coverage
|
||||||
|
examples.QsStartSvr()
|
||||||
|
assertSucceed(t, examples.QsFireRequest())
|
||||||
|
assertSucceed(t, examples.MsgFireRequest())
|
||||||
|
assertSucceed(t, examples.SagaBarrierFireRequest())
|
||||||
|
assertSucceed(t, examples.SagaFireRequest())
|
||||||
|
assertSucceed(t, examples.TccBarrierFireRequest())
|
||||||
|
assertSucceed(t, examples.TccFireRequest())
|
||||||
|
assertSucceed(t, examples.XaFireRequest())
|
||||||
|
}
|
||||||
39
dtmsvr/trans_msg_test.go
Normal file
39
dtmsvr/trans_msg_test.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package dtmsvr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/yedf/dtm/examples"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMsg(t *testing.T) {
|
||||||
|
|
||||||
|
msgNormal(t)
|
||||||
|
msgPending(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func msgNormal(t *testing.T) {
|
||||||
|
msg := genMsg("gid-msg-normal")
|
||||||
|
msg.Submit()
|
||||||
|
assert.Equal(t, "submitted", getTransStatus(msg.Gid))
|
||||||
|
WaitTransProcessed(msg.Gid)
|
||||||
|
assert.Equal(t, []string{"succeed", "succeed"}, getBranchesStatus(msg.Gid))
|
||||||
|
assert.Equal(t, "succeed", getTransStatus(msg.Gid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func msgPending(t *testing.T) {
|
||||||
|
msg := genMsg("gid-msg-normal-pending")
|
||||||
|
msg.Prepare("")
|
||||||
|
assert.Equal(t, "prepared", getTransStatus(msg.Gid))
|
||||||
|
examples.MainSwitch.CanSubmitResult.SetOnce("PENDING")
|
||||||
|
CronTransOnce(60 * time.Second)
|
||||||
|
assert.Equal(t, "prepared", getTransStatus(msg.Gid))
|
||||||
|
examples.MainSwitch.TransInResult.SetOnce("PENDING")
|
||||||
|
CronTransOnce(60 * time.Second)
|
||||||
|
assert.Equal(t, "submitted", getTransStatus(msg.Gid))
|
||||||
|
CronTransOnce(60 * time.Second)
|
||||||
|
assert.Equal(t, []string{"succeed", "succeed"}, getBranchesStatus(msg.Gid))
|
||||||
|
assert.Equal(t, "succeed", getTransStatus(msg.Gid))
|
||||||
|
}
|
||||||
39
dtmsvr/trans_saga_barrier_test.go
Normal file
39
dtmsvr/trans_saga_barrier_test.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package dtmsvr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/yedf/dtm/dtmcli"
|
||||||
|
"github.com/yedf/dtm/examples"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSagaBarrier(t *testing.T) {
|
||||||
|
|
||||||
|
sagaBarrierNormal(t)
|
||||||
|
sagaBarrierRollback(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sagaBarrierNormal(t *testing.T) {
|
||||||
|
req := &examples.TransReq{Amount: 30}
|
||||||
|
saga := dtmcli.NewSaga(DtmServer).
|
||||||
|
Add(Busi+"/SagaBTransOut", Busi+"/SagaBTransOutCompensate", req).
|
||||||
|
Add(Busi+"/SagaBTransIn", Busi+"/SagaBTransInCompensate", req)
|
||||||
|
logrus.Printf("busi trans submit")
|
||||||
|
err := saga.Submit()
|
||||||
|
e2p(err)
|
||||||
|
WaitTransProcessed(saga.Gid)
|
||||||
|
assert.Equal(t, []string{"prepared", "succeed", "prepared", "succeed"}, getBranchesStatus(saga.Gid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func sagaBarrierRollback(t *testing.T) {
|
||||||
|
saga := dtmcli.NewSaga(DtmServer).
|
||||||
|
Add(Busi+"/SagaBTransOut", Busi+"/SagaBTransOutCompensate", &examples.TransReq{Amount: 30}).
|
||||||
|
Add(Busi+"/SagaBTransIn", Busi+"/SagaBTransInCompensate", &examples.TransReq{Amount: 30, TransInResult: "FAILURE"})
|
||||||
|
logrus.Printf("busi trans submit")
|
||||||
|
err := saga.Submit()
|
||||||
|
e2p(err)
|
||||||
|
WaitTransProcessed(saga.Gid)
|
||||||
|
assert.Equal(t, "failed", getTransStatus(saga.Gid))
|
||||||
|
}
|
||||||
44
dtmsvr/trans_saga_test.go
Normal file
44
dtmsvr/trans_saga_test.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package dtmsvr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/yedf/dtm/examples"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSaga(t *testing.T) {
|
||||||
|
|
||||||
|
sagaNormal(t)
|
||||||
|
sagaCommittedPending(t)
|
||||||
|
sagaRollback(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sagaNormal(t *testing.T) {
|
||||||
|
saga := genSaga("gid-noramlSaga", false, false)
|
||||||
|
saga.Submit()
|
||||||
|
WaitTransProcessed(saga.Gid)
|
||||||
|
assert.Equal(t, []string{"prepared", "succeed", "prepared", "succeed"}, getBranchesStatus(saga.Gid))
|
||||||
|
assert.Equal(t, "succeed", getTransStatus(saga.Gid))
|
||||||
|
transQuery(t, saga.Gid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sagaCommittedPending(t *testing.T) {
|
||||||
|
saga := genSaga("gid-committedPending", false, false)
|
||||||
|
examples.MainSwitch.TransInResult.SetOnce("PENDING")
|
||||||
|
saga.Submit()
|
||||||
|
WaitTransProcessed(saga.Gid)
|
||||||
|
assert.Equal(t, []string{"prepared", "prepared", "prepared", "prepared"}, getBranchesStatus(saga.Gid))
|
||||||
|
CronTransOnce(60 * time.Second)
|
||||||
|
assert.Equal(t, []string{"prepared", "succeed", "prepared", "succeed"}, getBranchesStatus(saga.Gid))
|
||||||
|
assert.Equal(t, "succeed", getTransStatus(saga.Gid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func sagaRollback(t *testing.T) {
|
||||||
|
saga := genSaga("gid-rollbackSaga2", false, true)
|
||||||
|
saga.Submit()
|
||||||
|
WaitTransProcessed(saga.Gid)
|
||||||
|
assert.Equal(t, "failed", getTransStatus(saga.Gid))
|
||||||
|
assert.Equal(t, []string{"succeed", "succeed", "succeed", "failed"}, getBranchesStatus(saga.Gid))
|
||||||
|
}
|
||||||
132
dtmsvr/trans_tcc_barrier_test.go
Normal file
132
dtmsvr/trans_tcc_barrier_test.go
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
package dtmsvr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/yedf/dtm/common"
|
||||||
|
"github.com/yedf/dtm/dtmcli"
|
||||||
|
"github.com/yedf/dtm/examples"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTccBarrier(t *testing.T) {
|
||||||
|
tccBarrierDisorder(t)
|
||||||
|
tccBarrierNormal(t)
|
||||||
|
tccBarrierRollback(t)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func tccBarrierRollback(t *testing.T) {
|
||||||
|
gid, err := dtmcli.TccGlobalTransaction(DtmServer, func(tcc *dtmcli.Tcc) (rerr error) {
|
||||||
|
res1, rerr := tcc.CallBranch(&examples.TransReq{Amount: 30}, Busi+"/TccBTransOutTry", Busi+"/TccBTransOutConfirm", Busi+"/TccBTransOutCancel")
|
||||||
|
e2p(rerr)
|
||||||
|
if res1.StatusCode() != 200 {
|
||||||
|
return fmt.Errorf("bad status code: %d", res1.StatusCode())
|
||||||
|
}
|
||||||
|
res2, rerr := tcc.CallBranch(&examples.TransReq{Amount: 30, TransInResult: "FAILURE"}, Busi+"/TccBTransInTry", Busi+"/TccBTransInConfirm", Busi+"/TccBTransInCancel")
|
||||||
|
e2p(rerr)
|
||||||
|
if res2.StatusCode() != 200 {
|
||||||
|
return fmt.Errorf("bad status code: %d", res2.StatusCode())
|
||||||
|
}
|
||||||
|
if strings.Contains(res2.String(), "FAILURE") {
|
||||||
|
return fmt.Errorf("branch trans in fail")
|
||||||
|
}
|
||||||
|
logrus.Printf("tcc returns: %s, %s", res1.String(), res2.String())
|
||||||
|
return
|
||||||
|
})
|
||||||
|
assert.Equal(t, err, fmt.Errorf("branch trans in fail"))
|
||||||
|
WaitTransProcessed(gid)
|
||||||
|
assert.Equal(t, "failed", getTransStatus(gid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func tccBarrierNormal(t *testing.T) {
|
||||||
|
_, err := dtmcli.TccGlobalTransaction(DtmServer, func(tcc *dtmcli.Tcc) (rerr error) {
|
||||||
|
res1, rerr := tcc.CallBranch(&examples.TransReq{Amount: 30}, Busi+"/TccBTransOutTry", Busi+"/TccBTransOutConfirm", Busi+"/TccBTransOutCancel")
|
||||||
|
e2p(rerr)
|
||||||
|
if res1.StatusCode() != 200 {
|
||||||
|
return fmt.Errorf("bad status code: %d", res1.StatusCode())
|
||||||
|
}
|
||||||
|
res2, rerr := tcc.CallBranch(&examples.TransReq{Amount: 30}, Busi+"/TccBTransInTry", Busi+"/TccBTransInConfirm", Busi+"/TccBTransInCancel")
|
||||||
|
e2p(rerr)
|
||||||
|
if res2.StatusCode() != 200 {
|
||||||
|
return fmt.Errorf("bad status code: %d", res2.StatusCode())
|
||||||
|
}
|
||||||
|
logrus.Printf("tcc returns: %s, %s", res1.String(), res2.String())
|
||||||
|
return
|
||||||
|
})
|
||||||
|
e2p(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func tccBarrierDisorder(t *testing.T) {
|
||||||
|
timeoutChan := make(chan string, 2)
|
||||||
|
finishedChan := make(chan string, 2)
|
||||||
|
gid, err := dtmcli.TccGlobalTransaction(DtmServer, func(tcc *dtmcli.Tcc) (rerr error) {
|
||||||
|
body := &examples.TransReq{Amount: 30}
|
||||||
|
tryURL := Busi + "/TccBTransOutTry"
|
||||||
|
confirmURL := Busi + "/TccBTransOutConfirm"
|
||||||
|
cancelURL := Busi + "/TccBSleepCancel"
|
||||||
|
// 请参见子事务屏障里的时序图,这里为了模拟该时序图,手动拆解了callbranch
|
||||||
|
branchID := tcc.NewBranchID()
|
||||||
|
sleeped := false
|
||||||
|
app.POST(examples.BusiAPI+"/TccBSleepCancel", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
|
||||||
|
res, err := examples.TccBarrierTransOutCancel(c)
|
||||||
|
if !sleeped {
|
||||||
|
sleeped = true
|
||||||
|
logrus.Printf("sleep before cancel return")
|
||||||
|
<-timeoutChan
|
||||||
|
finishedChan <- "1"
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
|
}))
|
||||||
|
// 注册子事务
|
||||||
|
r, err := common.RestyClient.R().
|
||||||
|
SetBody(&M{
|
||||||
|
"gid": tcc.Gid,
|
||||||
|
"branch_id": branchID,
|
||||||
|
"trans_type": "tcc",
|
||||||
|
"status": "prepared",
|
||||||
|
"data": string(common.MustMarshal(body)),
|
||||||
|
"try": tryURL,
|
||||||
|
"confirm": confirmURL,
|
||||||
|
"cancel": cancelURL,
|
||||||
|
}).
|
||||||
|
Post(tcc.Dtm + "/registerTccBranch")
|
||||||
|
e2p(err)
|
||||||
|
assert.True(t, strings.Contains(r.String(), "SUCCESS"))
|
||||||
|
go func() {
|
||||||
|
logrus.Printf("sleeping to wait for tcc try timeout")
|
||||||
|
<-timeoutChan
|
||||||
|
r, _ = common.RestyClient.R().
|
||||||
|
SetBody(body).
|
||||||
|
SetQueryParams(common.MS{
|
||||||
|
"dtm": tcc.Dtm,
|
||||||
|
"gid": tcc.Gid,
|
||||||
|
"branch_id": branchID,
|
||||||
|
"trans_type": "tcc",
|
||||||
|
"branch_type": "try",
|
||||||
|
}).
|
||||||
|
Post(tryURL)
|
||||||
|
assert.True(t, strings.Contains(r.String(), "FAILURE"))
|
||||||
|
finishedChan <- "1"
|
||||||
|
}()
|
||||||
|
logrus.Printf("cron to timeout and then call cancel")
|
||||||
|
go CronTransOnce(60 * time.Second)
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
logrus.Printf("cron to timeout and then call cancelled twice")
|
||||||
|
CronTransOnce(60 * time.Second)
|
||||||
|
timeoutChan <- "wake"
|
||||||
|
timeoutChan <- "wake"
|
||||||
|
<-finishedChan
|
||||||
|
<-finishedChan
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
return fmt.Errorf("a cancelled tcc")
|
||||||
|
})
|
||||||
|
assert.Error(t, err, fmt.Errorf("a cancelled tcc"))
|
||||||
|
assert.Equal(t, []string{"succeed", "prepared", "prepared"}, getBranchesStatus(gid))
|
||||||
|
assert.Equal(t, "failed", getTransStatus(gid))
|
||||||
|
}
|
||||||
38
dtmsvr/trans_tcc_test.go
Normal file
38
dtmsvr/trans_tcc_test.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
package dtmsvr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/yedf/dtm/dtmcli"
|
||||||
|
"github.com/yedf/dtm/examples"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTcc(t *testing.T) {
|
||||||
|
tccNormal(t)
|
||||||
|
tccRollback(t)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func tccNormal(t *testing.T) {
|
||||||
|
data := &examples.TransReq{Amount: 30}
|
||||||
|
_, err := dtmcli.TccGlobalTransaction(examples.DtmServer, func(tcc *dtmcli.Tcc) (rerr error) {
|
||||||
|
_, rerr = tcc.CallBranch(data, Busi+"/TransOut", Busi+"/TransOutConfirm", Busi+"/TransOutRevert")
|
||||||
|
e2p(rerr)
|
||||||
|
_, rerr = tcc.CallBranch(data, Busi+"/TransIn", Busi+"/TransInConfirm", Busi+"/TransInRevert")
|
||||||
|
e2p(rerr)
|
||||||
|
return
|
||||||
|
})
|
||||||
|
e2p(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func tccRollback(t *testing.T) {
|
||||||
|
data := &examples.TransReq{Amount: 30, TransInResult: "FAILURE"}
|
||||||
|
_, err := dtmcli.TccGlobalTransaction(examples.DtmServer, func(tcc *dtmcli.Tcc) (rerr error) {
|
||||||
|
_, rerr = tcc.CallBranch(data, Busi+"/TransOut", Busi+"/TransOutConfirm", Busi+"/TransOutRevert")
|
||||||
|
e2p(rerr)
|
||||||
|
_, rerr = tcc.CallBranch(data, Busi+"/TransIn", Busi+"/TransInConfirm", Busi+"/TransInRevert")
|
||||||
|
e2p(rerr)
|
||||||
|
return
|
||||||
|
})
|
||||||
|
e2p(err)
|
||||||
|
}
|
||||||
50
dtmsvr/trans_xa_test.go
Normal file
50
dtmsvr/trans_xa_test.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package dtmsvr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/yedf/dtm/common"
|
||||||
|
"github.com/yedf/dtm/dtmcli"
|
||||||
|
"github.com/yedf/dtm/examples"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestXa(t *testing.T) {
|
||||||
|
|
||||||
|
xaNormal(t)
|
||||||
|
xaRollback(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func xaNormal(t *testing.T) {
|
||||||
|
xc := examples.XaClient
|
||||||
|
gid, err := xc.XaGlobalTransaction(func(xa *dtmcli.Xa) error {
|
||||||
|
req := examples.GenTransReq(30, false, false)
|
||||||
|
resp, err := xa.CallBranch(req, examples.Busi+"/TransOutXa")
|
||||||
|
common.CheckRestySuccess(resp, err)
|
||||||
|
resp, err = xa.CallBranch(req, examples.Busi+"/TransInXa")
|
||||||
|
common.CheckRestySuccess(resp, err)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
e2p(err)
|
||||||
|
WaitTransProcessed(gid)
|
||||||
|
assert.Equal(t, []string{"prepared", "succeed", "prepared", "succeed"}, getBranchesStatus(gid))
|
||||||
|
}
|
||||||
|
|
||||||
|
func xaRollback(t *testing.T) {
|
||||||
|
xc := examples.XaClient
|
||||||
|
gid, err := xc.XaGlobalTransaction(func(xa *dtmcli.Xa) error {
|
||||||
|
req := examples.GenTransReq(30, false, true)
|
||||||
|
resp, err := xa.CallBranch(req, examples.Busi+"/TransOutXa")
|
||||||
|
common.CheckRestySuccess(resp, err)
|
||||||
|
resp, err = xa.CallBranch(req, examples.Busi+"/TransInXa")
|
||||||
|
common.CheckRestySuccess(resp, err)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
logrus.Errorf("global transaction failed, so rollback")
|
||||||
|
}
|
||||||
|
WaitTransProcessed(gid)
|
||||||
|
assert.Equal(t, []string{"succeed", "prepared"}, getBranchesStatus(gid))
|
||||||
|
assert.Equal(t, "failed", getTransStatus(gid))
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user