You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

transaction_executor_test.go 12 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package tm
  18. import (
  19. "context"
  20. "reflect"
  21. "testing"
  22. "time"
  23. "github.com/agiledragon/gomonkey/v2"
  24. "github.com/pkg/errors"
  25. "github.com/stretchr/testify/assert"
  26. "github.com/seata/seata-go/pkg/protocol/message"
  27. )
  28. func TestTransactionExecutorBegin(t *testing.T) {
  29. type Test struct {
  30. ctx context.Context
  31. gc *GtxConfig
  32. xid string
  33. wantHasMock bool
  34. wantMockTargetName string
  35. wantMockFunction interface{}
  36. wantHasError bool
  37. wantErrorString string
  38. wantUseExist bool
  39. wantBeginNew bool
  40. }
  41. gts := []Test{
  42. {
  43. ctx: context.Background(),
  44. gc: &GtxConfig{
  45. Name: "MockGtxName",
  46. Propagation: NotSupported,
  47. },
  48. xid: "123456",
  49. },
  50. {
  51. ctx: context.Background(),
  52. gc: &GtxConfig{
  53. Name: "MockGtxName",
  54. Propagation: Supports,
  55. },
  56. xid: "123456",
  57. wantUseExist: true,
  58. },
  59. {
  60. ctx: context.Background(),
  61. gc: &GtxConfig{
  62. Name: "MockGtxName",
  63. Propagation: RequiresNew,
  64. },
  65. xid: "123456",
  66. wantHasMock: true,
  67. wantMockTargetName: "Begin",
  68. wantMockFunction: func(_ *GlobalTransactionManager, ctx context.Context, i time.Duration) error {
  69. SetXID(ctx, "123456")
  70. return nil
  71. },
  72. wantBeginNew: true,
  73. },
  74. // use exist
  75. {
  76. ctx: context.Background(),
  77. gc: &GtxConfig{
  78. Name: "MockGtxName",
  79. Propagation: Required,
  80. },
  81. xid: "123456",
  82. wantUseExist: true,
  83. },
  84. //Begin new
  85. {
  86. ctx: context.Background(),
  87. gc: &GtxConfig{
  88. Name: "MockGtxName",
  89. Propagation: Required,
  90. },
  91. wantHasMock: true,
  92. wantMockTargetName: "Begin",
  93. wantMockFunction: func(_ *GlobalTransactionManager, ctx context.Context, i time.Duration) error {
  94. SetXID(ctx, "123456")
  95. return nil
  96. },
  97. wantBeginNew: true,
  98. },
  99. // has error
  100. {
  101. ctx: context.Background(),
  102. gc: &GtxConfig{
  103. Name: "MockGtxName",
  104. Propagation: Never,
  105. },
  106. xid: "123456",
  107. wantHasError: true,
  108. wantErrorString: "existing transaction found for transaction marked with pg 'never', xid = 123456",
  109. },
  110. // has not error
  111. {
  112. ctx: context.Background(),
  113. gc: &GtxConfig{
  114. Name: "MockGtxName",
  115. Propagation: Never,
  116. },
  117. },
  118. // use exist
  119. {
  120. ctx: context.Background(),
  121. gc: &GtxConfig{
  122. Name: "MockGtxName",
  123. Propagation: Mandatory,
  124. },
  125. xid: "123456",
  126. wantUseExist: true,
  127. },
  128. // has error
  129. {
  130. ctx: context.Background(),
  131. gc: &GtxConfig{
  132. Name: "MockGtxName",
  133. Propagation: Mandatory,
  134. },
  135. wantHasError: true,
  136. wantErrorString: "no existing transaction found for transaction marked with pg 'mandatory'",
  137. },
  138. // default case
  139. {
  140. ctx: context.Background(),
  141. gc: &GtxConfig{
  142. Name: "MockGtxName",
  143. Propagation: -1,
  144. },
  145. wantHasError: true,
  146. wantErrorString: "not Supported Propagation:-1",
  147. },
  148. }
  149. for i, v := range gts {
  150. t.Logf("Case %v: %+v", i, v)
  151. var stub *gomonkey.Patches
  152. // set up stub
  153. if v.wantHasMock {
  154. stub = gomonkey.ApplyMethod(reflect.TypeOf(GetGlobalTransactionManager()), v.wantMockTargetName, v.wantMockFunction)
  155. }
  156. v.ctx = InitSeataContext(v.ctx)
  157. if v.xid != "" {
  158. SetXID(v.ctx, v.xid)
  159. }
  160. err := begin(v.ctx, v.gc)
  161. if v.wantHasError {
  162. assert.NotNil(t, err)
  163. } else {
  164. assert.Nil(t, err)
  165. }
  166. if v.wantBeginNew {
  167. assert.Equal(t, Launcher, *GetTxRole(v.ctx))
  168. }
  169. if v.wantUseExist {
  170. assert.Equal(t, Participant, *GetTxRole(v.ctx))
  171. }
  172. // rest up stub
  173. if v.wantHasMock {
  174. stub.Reset()
  175. }
  176. }
  177. }
  178. func TestTransactionExecutorCommit(t *testing.T) {
  179. ctx := context.Background()
  180. ctx = InitSeataContext(ctx)
  181. SetTxRole(ctx, Launcher)
  182. SetTxStatus(ctx, message.GlobalStatusBegin)
  183. SetXID(ctx, "")
  184. assert.Equal(t, "Commit xid should not be empty", commitOrRollback(ctx, true).Error())
  185. }
  186. func TestTransactionExecurotRollback(t *testing.T) {
  187. ctx := context.Background()
  188. ctx = InitSeataContext(ctx)
  189. SetTxRole(ctx, Launcher)
  190. SetTxStatus(ctx, message.GlobalStatusBegin)
  191. SetXID(ctx, "")
  192. errActual := commitOrRollback(ctx, false)
  193. assert.Equal(t, "Rollback xid should not be empty", errActual.Error())
  194. }
  195. func TestCommitOrRollback(t *testing.T) {
  196. type Test struct {
  197. ctx context.Context
  198. tx GlobalTransaction
  199. ok bool
  200. wantHasMock bool
  201. wantMockTargetName string
  202. wantMockFunction interface{}
  203. wantHasError bool
  204. wantErrorString string
  205. }
  206. gts := []Test{
  207. {
  208. ctx: context.Background(),
  209. tx: GlobalTransaction{
  210. TxRole: UnKnow,
  211. },
  212. wantHasError: true,
  213. wantErrorString: "global transaction role is UnKnow.",
  214. },
  215. //ok with nil
  216. {
  217. ctx: context.Background(),
  218. tx: GlobalTransaction{
  219. TxRole: Launcher,
  220. },
  221. ok: true,
  222. wantHasMock: true,
  223. wantMockTargetName: "Commit",
  224. wantMockFunction: func(_ *GlobalTransactionManager, ctx context.Context, gtr *GlobalTransaction) error {
  225. return nil
  226. },
  227. },
  228. //ok with error
  229. {
  230. ctx: context.Background(),
  231. tx: GlobalTransaction{
  232. TxRole: Launcher,
  233. },
  234. ok: true,
  235. wantHasMock: true,
  236. wantMockTargetName: "Commit",
  237. wantMockFunction: func(_ *GlobalTransactionManager, ctx context.Context, gtr *GlobalTransaction) error {
  238. return errors.New("Mock error")
  239. },
  240. wantHasError: true,
  241. wantErrorString: "Mock error",
  242. },
  243. // false with nil
  244. {
  245. ctx: context.Background(),
  246. tx: GlobalTransaction{
  247. TxRole: Launcher,
  248. },
  249. ok: false,
  250. wantHasMock: true,
  251. wantMockTargetName: "Rollback",
  252. wantMockFunction: func(_ *GlobalTransactionManager, ctx context.Context, gtr *GlobalTransaction) error {
  253. return nil
  254. },
  255. },
  256. // false with error
  257. {
  258. ctx: context.Background(),
  259. tx: GlobalTransaction{
  260. TxRole: Launcher,
  261. },
  262. ok: false,
  263. wantHasMock: true,
  264. wantMockTargetName: "Rollback",
  265. wantMockFunction: func(_ *GlobalTransactionManager, ctx context.Context, gtr *GlobalTransaction) error {
  266. return errors.New("Mock error")
  267. },
  268. wantHasError: true,
  269. wantErrorString: "Mock error",
  270. },
  271. {
  272. ctx: context.Background(),
  273. tx: GlobalTransaction{
  274. TxRole: Participant,
  275. },
  276. },
  277. }
  278. for i, v := range gts {
  279. t.Logf("Case %v: %+v", i, v)
  280. v.ctx = InitSeataContext(v.ctx)
  281. SetTx(v.ctx, &v.tx)
  282. var stub *gomonkey.Patches
  283. if v.wantHasMock {
  284. stub = gomonkey.ApplyMethod(reflect.TypeOf(GetGlobalTransactionManager()), v.wantMockTargetName, v.wantMockFunction)
  285. }
  286. err := commitOrRollback(v.ctx, v.ok)
  287. if v.wantHasError {
  288. assert.Equal(t, v.wantErrorString, err.Error())
  289. } else {
  290. assert.Nil(t, err)
  291. }
  292. if v.wantHasMock {
  293. stub.Reset()
  294. }
  295. }
  296. }
  297. func TestClearTxConf(t *testing.T) {
  298. ctx := InitSeataContext(context.Background())
  299. SetTx(ctx, &GlobalTransaction{
  300. Xid: "123456",
  301. TxName: "MockTxName",
  302. TxStatus: message.GlobalStatusBegin,
  303. TxRole: Launcher,
  304. })
  305. clearTxConf(ctx)
  306. assert.Equal(t, "123456", GetXID(ctx))
  307. assert.Equal(t, UnKnow, *GetTxRole(ctx))
  308. assert.Equal(t, message.GlobalStatusUnKnown, *GetTxStatus(ctx))
  309. assert.Equal(t, "", GetTxName(ctx))
  310. }
  311. func TestUseExistGtx(t *testing.T) {
  312. ctx := InitSeataContext(context.Background())
  313. SetXID(ctx, "123456")
  314. useExistGtx(ctx, &GtxConfig{
  315. Name: "useExistGtxMock",
  316. })
  317. assert.Equal(t, Participant, *GetTxRole(ctx))
  318. assert.Equal(t, message.GlobalStatusBegin, *GetTxStatus(ctx))
  319. }
  320. func TestBeginNewGtx(t *testing.T) {
  321. ctx := InitSeataContext(context.Background())
  322. g := &GtxConfig{
  323. Name: "beginNewGtxMock",
  324. }
  325. // case return nil
  326. gomonkey.ApplyMethod(reflect.TypeOf(GetGlobalTransactionManager()), "Begin",
  327. func(_ *GlobalTransactionManager, ctx context.Context, timeout time.Duration) error {
  328. return nil
  329. })
  330. assert.Nil(t, beginNewGtx(ctx, g))
  331. assert.Equal(t, Launcher, *GetTxRole(ctx))
  332. assert.Equal(t, g.Name, GetTxName(ctx))
  333. assert.Equal(t, message.GlobalStatusBegin, *GetTxStatus(ctx))
  334. // case return error
  335. err := errors.New("Mock Exception")
  336. gomonkey.ApplyMethod(reflect.TypeOf(GetGlobalTransactionManager()), "Begin",
  337. func(_ *GlobalTransactionManager, ctx context.Context, timeout time.Duration) error {
  338. return err
  339. })
  340. assert.Error(t, beginNewGtx(ctx, g))
  341. }
  342. func TestWithGlobalTx(t *testing.T) {
  343. callbackError := func(ctx context.Context) error {
  344. return errors.New("mock callback error")
  345. }
  346. callbackNil := func(ctx context.Context) error {
  347. return nil
  348. }
  349. type testCase struct {
  350. GtxConfig *GtxConfig
  351. occurError bool
  352. errMessage string
  353. callbackErr bool
  354. mockBeginFunc interface{}
  355. mockBeginTarget interface{}
  356. mockSecondPhaseFunc interface{}
  357. mockSecondPhaseTarget interface{}
  358. secondErr bool
  359. callback CallbackWithCtx
  360. }
  361. gts := []testCase{
  362. // case TxName is nil
  363. {
  364. GtxConfig: &GtxConfig{},
  365. occurError: true,
  366. errMessage: "global transaction name is required.",
  367. },
  368. // case GtxConfig is nil
  369. {
  370. occurError: true,
  371. errMessage: "global transaction config info is required.",
  372. },
  373. // case mock begin return error
  374. {
  375. GtxConfig: &GtxConfig{
  376. Name: "MockGtxConfig",
  377. },
  378. occurError: true,
  379. errMessage: "mock begin",
  380. mockBeginTarget: begin,
  381. mockBeginFunc: func(ctx context.Context, gc *GtxConfig) error {
  382. return errors.New("mock begin")
  383. },
  384. },
  385. // case callback return error
  386. {
  387. GtxConfig: &GtxConfig{
  388. Name: "MockGtxConfig",
  389. },
  390. callbackErr: true,
  391. callback: callbackError,
  392. mockBeginTarget: begin,
  393. mockBeginFunc: func(ctx context.Context, gc *GtxConfig) error {
  394. return nil
  395. },
  396. },
  397. // case callback return nil
  398. {
  399. GtxConfig: &GtxConfig{
  400. Name: "MockGtxConfig",
  401. },
  402. mockBeginTarget: begin,
  403. mockBeginFunc: func(ctx context.Context, gc *GtxConfig) error {
  404. SetXID(ctx, "123456")
  405. return nil
  406. },
  407. callback: callbackNil,
  408. mockSecondPhaseTarget: commitOrRollback,
  409. mockSecondPhaseFunc: func(ctx context.Context, s bool) error {
  410. return nil
  411. },
  412. },
  413. // case second mock error
  414. {
  415. GtxConfig: &GtxConfig{
  416. Name: "MockGtxConfig",
  417. },
  418. mockBeginTarget: begin,
  419. mockBeginFunc: func(ctx context.Context, gc *GtxConfig) error {
  420. SetXID(ctx, "123456")
  421. return nil
  422. },
  423. callback: callbackNil,
  424. mockSecondPhaseTarget: commitOrRollback,
  425. mockSecondPhaseFunc: func(ctx context.Context, s bool) error {
  426. return errors.New("second error mock")
  427. },
  428. secondErr: true,
  429. },
  430. }
  431. for i, v := range gts {
  432. t.Logf("Case %v: %+v", i, v)
  433. var beginStub *gomonkey.Patches
  434. var secondStub *gomonkey.Patches
  435. if v.mockBeginTarget != nil {
  436. beginStub = gomonkey.ApplyFunc(v.mockBeginTarget, v.mockBeginFunc)
  437. }
  438. if v.mockSecondPhaseTarget != nil {
  439. secondStub = gomonkey.ApplyFunc(v.mockSecondPhaseTarget, v.mockSecondPhaseFunc)
  440. }
  441. ctx := context.Background()
  442. err := WithGlobalTx(ctx, v.GtxConfig, v.callback)
  443. if v.occurError {
  444. assert.Equal(t, v.errMessage, err.Error())
  445. }
  446. if v.callbackErr {
  447. assert.NotNil(t, err)
  448. }
  449. if v.secondErr {
  450. assert.NotNil(t, err)
  451. }
  452. if v.mockBeginTarget != nil {
  453. beginStub.Reset()
  454. }
  455. if v.mockSecondPhaseTarget != nil {
  456. secondStub.Reset()
  457. }
  458. }
  459. }