{"id":17283287,"url":"https://github.com/agiledragon/trans-dsl","last_synced_at":"2026-03-14T13:15:05.859Z","repository":{"id":57489120,"uuid":"142313662","full_name":"agiledragon/trans-dsl","owner":"agiledragon","description":"a transaction model framework, seems simple but powerful","archived":false,"fork":false,"pushed_at":"2021-12-03T01:29:54.000Z","size":120,"stargazers_count":70,"open_issues_count":0,"forks_count":23,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-01T18:01:51.340Z","etag":null,"topics":["dsl","framework","go","model","transaction"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/agiledragon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-07-25T14:45:07.000Z","updated_at":"2024-10-07T17:12:12.000Z","dependencies_parsed_at":"2022-08-29T22:11:44.295Z","dependency_job_id":null,"html_url":"https://github.com/agiledragon/trans-dsl","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agiledragon%2Ftrans-dsl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agiledragon%2Ftrans-dsl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agiledragon%2Ftrans-dsl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agiledragon%2Ftrans-dsl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agiledragon","download_url":"https://codeload.github.com/agiledragon/trans-dsl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244236061,"owners_count":20420753,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dsl","framework","go","model","transaction"],"created_at":"2024-10-15T09:50:56.680Z","updated_at":"2026-03-14T13:15:05.819Z","avatar_url":"https://github.com/agiledragon.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Transaction DSL\n\ntrans-dsl is a transaction model framework in golang,  can be used in complex business scenes.\n\n## Introduction\nIn some complex domains, a business process may involve the interaction of multiple messages, which may be synchronous messages, asynchronous messages, or even system calls. We explicitly model the operation behavior of message interaction, and call the operation behavior of a message interaction as Action, then the flow chart of the business corresponds to an Action sequence. In general, a single scenario business process corresponds to a transaction process. Based on the transaction model framework, business developers can not only express all business processes in a simple and complete manner at a higher level, but also apply and maintain transaction models at low cost.\n\n## Chinese reader references\n+ [软件设计的演变过程](https://www.jianshu.com/p/18d1d582f5c2)\n+ [DDD分层架构的三种模式](https://www.jianshu.com/p/a775836c7e25)\n+ [Golang事务模型](https://www.jianshu.com/p/b7e874f6d3e8)\n\n## Features\n+ support synchronous messages\n+ support system calls\n+ support asynchronous messages\n\n## Installation\n------------\n\t$ go get github.com/agiledragon/trans-dsl\n\t\n## Keyword\n+ optional\n+ loop\n+ retry\n+ repeat\n+ wait\n+ concurrent\n+ procedure\n+ succ\n+ fail\n+ not\n+ allof\n+ anyof\n\n## Using Transaction DSL\n\nFirstly, let's look at a transaction example.\n\u003eDuring the synchronization request processing from S1 to S2, the perspective of standing at S1 is an Action, while the perspective of standing at S2 is a transaction.\n\n![](trans-example.png)\n\n```go\nfunc newS1ReqTrans() *transdsl.Transaction {\n\ttrans := \u0026transdsl.Transaction{\n\t\tFragments: []transdsl.Fragment{\n\t\t\tnew(action.Action1),\n\t\t\t\u0026transdsl.Optional{\n\t\t\t\tSpec:   new(spec.ShouldExecAction2),\n\t\t\t\tIfFrag: new(action.Action2),\n\t\t\t},\n\t\t\t\u0026transdsl.Loop{\n\t\t\t\tFuncVar: newProcedure1,\n\t\t\t},\n\t\t\tnew(action.Action3),\n\t\t},\n\t}\n\treturn trans\n}\n\nfunc newProcedure1() transdsl.Fragment {\n\tprocedure := \u0026transdsl.Procedure{\n\t\tFragments: []transdsl.Fragment{\n\t\t\tnew(action.Action11),\n\t\t\t\u0026transdsl.Optional{\n\t\t\t\tSpec:   new(spec.ShouldExecProcedure2),\n\t\t\t\tIfFrag: newProcedure2(),\n\t\t\t},\n\t\t\tnew(action.Action12),\n\t\t},\n\t}\n\treturn procedure\n}\n\nfunc newProcedure2() transdsl.Fragment {\n\tprocedure := \u0026transdsl.Procedure{\n\t\tFragments: []transdsl.Fragment{\n\t\t\tnew(action.Action21),\n\t\t\tnew(action.Action22),\n\t\t},\n\t}\n\treturn procedure\n}\n\n\n```\n\n\nThe following just make some tests as typical examples.\n**Please refer to the test cases, very complete and detailed.**\n\n\n### optional\n\n```go\nimport (\n\t\"github.com/agiledragon/trans-dsl\"\n\t\"github.com/agiledragon/trans-dsl/test/context\"\n\t\"github.com/agiledragon/trans-dsl/test/context/action\"\n\t\"github.com/agiledragon/trans-dsl/test/context/spec\"\n\t. \"github.com/smartystreets/goconvey/convey\"\n\t\"testing\"\n)\n\nfunc newIfTrans() *transdsl.Transaction {\n\ttrans := \u0026transdsl.Transaction{\n\t\tFragments: []transdsl.Fragment{\n\t\t\t\u0026transdsl.Optional{\n\t\t\t\tSpec:   new(spec.IsAbcExist),\n\t\t\t\tIfFrag: new(action.StubConnectAbc),\n\t\t\t},\n\t\t\tnew(action.StubActivateSomething),\n\t\t},\n\t}\n\treturn trans\n}\n\nfunc newElseTrans() *transdsl.Transaction {\n\ttrans := \u0026transdsl.Transaction{\n\t\tFragments: []transdsl.Fragment{\n\t\t\t\u0026transdsl.Optional{\n\t\t\t\tSpec:     new(spec.IsAbcExist),\n\t\t\t\tIfFrag:   new(action.StubConnectAbc),\n\t\t\t\tElseFrag: new(action.StubConnectDef),\n\t\t\t},\n\t\t\tnew(action.StubActivateSomething),\n\t\t},\n\t}\n\treturn trans\n}\n\nfunc TestIfTrans(t *testing.T) {\n\ttrans := newIfTrans()\n\tConvey(\"TestIfTrans\", t, func() {\n\n\t\tConvey(\"trans exec succ when spec is true\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tAbc: \"abc\",\n\t\t\t\t\tY:   1,\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err, ShouldEqual, nil)\n\t\t\tSo(transInfo.AppInfo.(*context.StubInfo).Y, ShouldEqual, 2)\n\t\t})\n\n\t\tConvey(\"trans exec succ when spec is false\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tAbc: \"def\",\n\t\t\t\t\tY:   1,\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err, ShouldEqual, nil)\n\t\t\tSo(transInfo.AppInfo.(*context.StubInfo).Y, ShouldEqual, 1)\n\t\t})\n\n\t\tConvey(\"iffrag rollback\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tX:   \"test\",\n\t\t\t\t\tAbc: \"abc\",\n\t\t\t\t\tY:   1,\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err, ShouldNotEqual, nil)\n\t\t\tSo(transInfo.AppInfo.(*context.StubInfo).Y, ShouldEqual, 0)\n\t\t})\n\t})\n}\n\nfunc TestElseTrans(t *testing.T) {\n\ttrans := newElseTrans()\n\tConvey(\"TestElseTrans\", t, func() {\n\n\t\tConvey(\"trans exec succ when spec is false\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tAbc: \"def\",\n\t\t\t\t\tY:   1,\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err, ShouldEqual, nil)\n\t\t\tSo(transInfo.AppInfo.(*context.StubInfo).Y, ShouldEqual, 3)\n\t\t})\n\n\t\tConvey(\"elsefrag rollback\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tX:   \"test\",\n\t\t\t\t\tAbc: \"def\",\n\t\t\t\t\tY:   1,\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err, ShouldNotEqual, nil)\n\t\t\tSo(transInfo.AppInfo.(*context.StubInfo).Y, ShouldEqual, -1)\n\t\t})\n\t})\n}\n\n```\n\n### loop\n```go\nimport (\n\t\"errors\"\n\t\"github.com/agiledragon/trans-dsl\"\n\t\"github.com/agiledragon/trans-dsl/test/context\"\n\t\"github.com/agiledragon/trans-dsl/test/context/action\"\n\t. \"github.com/smartystreets/goconvey/convey\"\n\t\"testing\"\n)\n\nfunc newLoopTrans() *transdsl.Transaction {\n\ttrans := \u0026transdsl.Transaction{\n\t\tFragments: []transdsl.Fragment{\n\t\t\tnew(action.StubGetSomething),\n\t\t\t\u0026transdsl.Loop{\n\t\t\t\tFuncVar:      newLoopProcedure,\n\t\t\t\tBreakErrs:    []error{errors.New(\"break1\"), errors.New(\"break2\")},\n\t\t\t\tContinueErrs: []error{errors.New(\"continue1\"), errors.New(\"continue2\")},\n\t\t\t},\n\t\t},\n\t}\n\treturn trans\n}\n\nfunc newLoopProcedure() transdsl.Fragment {\n\tprocedure := \u0026transdsl.Procedure{\n\t\tFragments: []transdsl.Fragment{\n\t\t\tnew(action.StubAttachSomething),\n\t\t\tnew(action.StubActivateSomething),\n\t\t},\n\t}\n\treturn procedure\n}\n\nfunc TestLoopTrans(t *testing.T) {\n\ttrans := newLoopTrans()\n\tConvey(\"TestLoopTrans\", t, func() {\n\n\t\tConvey(\"trans exec succ when loop 3 times\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tLoopValue: 1,\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err, ShouldEqual, nil)\n\t\t\tSo(transInfo.AppInfo.(*context.StubInfo).LoopValue, ShouldEqual, 4)\n\t\t})\n\n\t\tConvey(\"trans exec succ when second time break\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tLoopValue: 1,\n\t\t\t\t\tAbc:       \"break\",\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err.Error(), ShouldEqual, \"break2\")\n\t\t\tSo(transInfo.AppInfo.(*context.StubInfo).LoopValue, ShouldEqual, 2)\n\n\t\t})\n\n\t\tConvey(\"trans exec succ when third time continue\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tLoopValue: 1,\n\t\t\t\t\tAbc:       \"continue\",\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err.Error(), ShouldEqual, \"continue2\")\n\t\t\tSo(transInfo.AppInfo.(*context.StubInfo).LoopValue, ShouldEqual, 3)\n\n\t\t})\n\n\t\tConvey(\"trans exec fail\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tLoopValue: 1,\n\t\t\t\t\tX:         \"test\",\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err, ShouldNotEqual, nil)\n\t\t\tSo(transInfo.AppInfo.(*context.StubInfo).LoopValue, ShouldEqual, 1)\n\t\t})\n\t})\n}\n\n\n```\n\n### retry\n```go\nimport (\n\t\"errors\"\n\t\"github.com/agiledragon/trans-dsl\"\n\t\"github.com/agiledragon/trans-dsl/test/context\"\n\t\"github.com/agiledragon/trans-dsl/test/context/action\"\n\t. \"github.com/smartystreets/goconvey/convey\"\n\t\"testing\"\n)\n\nfunc newRetryTrans() *transdsl.Transaction {\n\ttrans := \u0026transdsl.Transaction{\n\t\tFragments: []transdsl.Fragment{\n\t\t\t\u0026transdsl.Retry{\n\t\t\t\tMaxTimes: 3,\n\t\t\t\tTimeLen:  100,\n\t\t\t\tFragment: new(action.StubConnectServer),\n\t\t\t\tErrs:     []error{errors.New(\"fatal\"), errors.New(\"panic\")},\n\t\t\t},\n\t\t},\n\t}\n\treturn trans\n}\n\nfunc TestRetryTrans(t *testing.T) {\n\ttrans := newRetryTrans()\n\tConvey(\"TestRetryTrans\", t, func() {\n\n\t\tConvey(\"trans exec succ when fail time is 1\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tFailTimes: 1,\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err, ShouldEqual, nil)\n\t\t})\n\n\t\tConvey(\"trans exec succ when fail time is 2\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tFailTimes: 2,\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err, ShouldEqual, nil)\n\t\t})\n\n\t\tConvey(\"trans exec fail when fail time is 3\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tFailTimes: 3,\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err, ShouldNotEqual, nil)\n\t\t})\n\n\t\tConvey(\"trans exec fail when error string is panic\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tFailTimes: 1,\n\t\t\t\t\tY:         -1,\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err.Error(), ShouldEqual, \"panic\")\n\t\t})\n\t})\n}\n\n```\n\n### wait\n```go\nimport (\n\t\"github.com/agiledragon/trans-dsl\"\n\t\"github.com/agiledragon/trans-dsl/test/context\"\n\t\"github.com/agiledragon/trans-dsl/test/context/action\"\n\t. \"github.com/smartystreets/goconvey/convey\"\n\t\"testing\"\n\t\"time\"\n)\n\nvar eventId = \"assign cmd\"\n\nfunc newWaitTrans() *transdsl.Transaction {\n\ttrans := \u0026transdsl.Transaction{\n\t\tFragments: []transdsl.Fragment{\n\t\t\tnew(action.StubTransferMoney),\n\t\t\t\u0026transdsl.Wait{\n\t\t\t\tEventId:  eventId,\n\t\t\t\tTimeout:  100,\n\t\t\t\tFragment: new(action.StubAssignCmd),\n\t\t\t},\n\t\t\tnew(action.StubAttachSomething),\n\t\t\tnew(action.StubActivateSomething),\n\t\t},\n\t}\n\treturn trans\n}\n\ntype TransObj struct {\n\ttrans     *transdsl.Transaction\n\ttransInfo *transdsl.TransInfo\n}\n\nvar transIds map[string]string\nvar transObjs map[string]TransObj\nvar key string\n\nfunc handleEvent(eventId string, eventContent []byte) {\n\ttransId := transIds[key]\n\ttransObj := transObjs[transId]\n\ttrans := transObj.trans\n\ttransInfo := transObj.transInfo\n\tstubInfo := transInfo.AppInfo.(*context.StubInfo)\n\tstubInfo.EventContent = eventContent\n\t\u003c-time.After(50 * time.Millisecond)\n\ttrans.HandleEvent(eventId, transInfo)\n}\n\nfunc TestWaitTrans(t *testing.T) {\n\ttrans := newWaitTrans()\n\ttransIds = make(map[string]string)\n\tkey = \"business id\"\n\ttransId := \"123456\"\n\ttransIds[key] = transId\n\n\ttransObjs = make(map[string]TransObj)\n\ttransInfo := \u0026transdsl.TransInfo{\n\t\tCh: make(chan struct{}),\n\t\tAppInfo: \u0026context.StubInfo{\n\t\t\tTransId: \"\",\n\t\t\tX:       \"info\",\n\t\t\tY:       1,\n\t\t},\n\t}\n\ttransObjs[transId] = TransObj{trans: trans, transInfo: transInfo}\n\tConvey(\"TestWaitTrans\", t, func() {\n\n\t\tConvey(\"wait succ\", func() {\n\t\t\tgo handleEvent(eventId, nil)\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err, ShouldEqual, nil)\n\t\t\tSo(transInfo.AppInfo.(*context.StubInfo).Y, ShouldEqual, 8)\n\t\t})\n\n\t\tConvey(\"wait timeout\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tCh: make(chan struct{}),\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tX: \"info\",\n\t\t\t\t\tY: 1,\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err.Error(), ShouldEqual, transdsl.ErrTimeout.Error())\n\t\t})\n\t})\n}\n\n\n```\n\n### allof\n```go\nimport (\n\t\"github.com/agiledragon/trans-dsl\"\n\t\"github.com/agiledragon/trans-dsl/test/context\"\n\t\"github.com/agiledragon/trans-dsl/test/context/action\"\n\t\"github.com/agiledragon/trans-dsl/test/context/spec\"\n\t. \"github.com/smartystreets/goconvey/convey\"\n\t\"testing\"\n)\n\nfunc newAllOfTrans() *transdsl.Transaction {\n\ttrans := \u0026transdsl.Transaction{\n\t\tFragments: []transdsl.Fragment{\n\t\t\t\u0026transdsl.Optional{\n\t\t\t\tSpec: \u0026transdsl.AllOf{\n\t\t\t\t\tSpecs: []transdsl.Specification{\n\t\t\t\t\t\tnew(spec.IsAbcExist),\n\t\t\t\t\t\tnew(spec.IsDefExist),\n\t\t\t\t\t\tnew(spec.IsGhiExist),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tIfFrag: new(action.StubConnectAbc),\n\t\t\t},\n\t\t\tnew(action.StubActivateSomething),\n\t\t},\n\t}\n\treturn trans\n}\n\nfunc TestAllOfTrans(t *testing.T) {\n\ttrans := newAllOfTrans()\n\tConvey(\"TestAllOfTrans\", t, func() {\n\n\t\tConvey(\"all specs are true\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tAbc: \"abc\",\n\t\t\t\t\tY:   1,\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err, ShouldEqual, nil)\n\t\t\tSo(transInfo.AppInfo.(*context.StubInfo).Y, ShouldEqual, 2)\n\t\t})\n\n\t\tConvey(\"one of specs is false\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tAbc: \"def\",\n\t\t\t\t\tY:   1,\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err, ShouldEqual, nil)\n\t\t\tSo(transInfo.AppInfo.(*context.StubInfo).Y, ShouldEqual, 1)\n\t\t})\n\t})\n}\n\n```\n\n### fail\n```go\nimport (\n\t\"errors\"\n\t\"github.com/agiledragon/trans-dsl\"\n\t\"github.com/agiledragon/trans-dsl/test/context\"\n\t\"github.com/agiledragon/trans-dsl/test/context/action\"\n\t\"github.com/agiledragon/trans-dsl/test/context/spec\"\n\t. \"github.com/smartystreets/goconvey/convey\"\n\t\"testing\"\n)\n\nvar ErrResourceInsufficient = errors.New(\"resource insufficient\")\n\nfunc newFailTrans() *transdsl.Transaction {\n\ttrans := \u0026transdsl.Transaction{\n\t\tFragments: []transdsl.Fragment{\n\t\t\tnew(action.StubAttachSomething),\n\t\t\t\u0026transdsl.Optional{\n\t\t\t\tSpec: new(spec.IsSomeResourceInsufficient),\n\t\t\t\tIfFrag: \u0026transdsl.Fail{\n\t\t\t\t\tErrCode: ErrResourceInsufficient,\n\t\t\t\t},\n\t\t\t},\n\t\t\tnew(action.StubActivateSomething),\n\t\t},\n\t}\n\treturn trans\n}\n\nfunc TestFailTrans(t *testing.T) {\n\ttrans := newFailTrans()\n\tConvey(\"TestFailTrans\", t, func() {\n\n\t\tConvey(\"spec is true\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tX:          \"insufficient\",\n\t\t\t\t\tSpecialNum: 1,\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err, ShouldEqual, ErrResourceInsufficient)\n\t\t\tSo(transInfo.AppInfo.(*context.StubInfo).SpecialNum, ShouldEqual, 10)\n\t\t})\n\n\t\tConvey(\"spec is false\", func() {\n\t\t\ttransInfo := \u0026transdsl.TransInfo{\n\t\t\t\tAppInfo: \u0026context.StubInfo{\n\t\t\t\t\tX:          \"sufficient\",\n\t\t\t\t\tSpecialNum: 1,\n\t\t\t\t},\n\t\t\t}\n\t\t\terr := trans.Start(transInfo)\n\t\t\tSo(err, ShouldEqual, nil)\n\t\t\tSo(transInfo.AppInfo.(*context.StubInfo).SpecialNum, ShouldEqual, 20)\n\t\t})\n\t})\n}\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagiledragon%2Ftrans-dsl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagiledragon%2Ftrans-dsl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagiledragon%2Ftrans-dsl/lists"}