github.com/ergo-services/ergo@v1.999.224/tests/saga_commit_test.go (about) 1 package tests 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/ergo-services/ergo" 8 "github.com/ergo-services/ergo/etf" 9 "github.com/ergo-services/ergo/gen" 10 "github.com/ergo-services/ergo/node" 11 ) 12 13 type argsSagaCommitArgs struct { 14 workerRes chan interface{} 15 sagaRes chan interface{} 16 testCaseDist bool 17 } 18 19 type testSagaCommitWorker1 struct { 20 gen.SagaWorker 21 } 22 23 func (w *testSagaCommitWorker1) HandleJobStart(process *gen.SagaWorkerProcess, job gen.SagaJob) error { 24 process.State = job.Value 25 process.SendResult(123) 26 args := process.State.(argsSagaCommitArgs) 27 args.workerRes <- "jobresult" 28 return nil 29 } 30 func (w *testSagaCommitWorker1) HandleJobCommit(process *gen.SagaWorkerProcess, final interface{}) { 31 args := process.State.(argsSagaCommitArgs) 32 args.workerRes <- final 33 return 34 } 35 func (w *testSagaCommitWorker1) HandleJobCancel(process *gen.SagaWorkerProcess, reason string) { 36 return 37 } 38 39 func (w *testSagaCommitWorker1) HandleWorkerTerminate(process *gen.SagaWorkerProcess, reason string) { 40 args := process.State.(argsSagaCommitArgs) 41 args.workerRes <- reason 42 } 43 44 type testSagaCommit1 struct { 45 gen.Saga 46 } 47 48 func (gs *testSagaCommit1) InitSaga(process *gen.SagaProcess, args ...etf.Term) (gen.SagaOptions, error) { 49 worker := &testSagaCommitWorker1{} 50 opts := gen.SagaOptions{ 51 Worker: worker, 52 } 53 process.State = args[0] 54 return opts, nil 55 } 56 57 func (gs *testSagaCommit1) HandleTxNew(process *gen.SagaProcess, id gen.SagaTransactionID, value interface{}) gen.SagaStatus { 58 args := process.State.(argsSagaCommitArgs) 59 args.sagaRes <- "newtx" 60 61 _, err := process.StartJob(id, gen.SagaJobOptions{}, args) 62 if err != nil { 63 panic(err) 64 } 65 66 if args.testCaseDist { 67 next := gen.SagaNext{ 68 Saga: gen.ProcessID{Name: "saga2", Node: "nodeGenSagaCommitDist02@localhost"}, 69 } 70 process.Next(id, next) 71 } 72 73 return gen.SagaStatusOK 74 } 75 76 func (gs *testSagaCommit1) HandleTxDone(process *gen.SagaProcess, id gen.SagaTransactionID, result interface{}) (interface{}, gen.SagaStatus) { 77 args := process.State.(argsSagaCommitArgs) 78 args.sagaRes <- "txdone" 79 return 6.28, gen.SagaStatusOK 80 } 81 82 func (gs *testSagaCommit1) HandleTxCancel(process *gen.SagaProcess, id gen.SagaTransactionID, reason string) gen.SagaStatus { 83 return gen.SagaStatusOK 84 } 85 86 func (gs *testSagaCommit1) HandleTxCommit(process *gen.SagaProcess, id gen.SagaTransactionID, final interface{}) gen.SagaStatus { 87 args := process.State.(argsSagaCommitArgs) 88 args.sagaRes <- final 89 return gen.SagaStatusOK 90 } 91 92 func (gs *testSagaCommit1) HandleTxResult(process *gen.SagaProcess, id gen.SagaTransactionID, from gen.SagaNextID, result interface{}) gen.SagaStatus { 93 args := process.State.(argsSagaCommitArgs) 94 args.sagaRes <- "txresult" 95 return gen.SagaStatusOK 96 } 97 98 func (gs *testSagaCommit1) HandleJobResult(process *gen.SagaProcess, id gen.SagaTransactionID, from gen.SagaJobID, result interface{}) gen.SagaStatus { 99 return gen.SagaStatusOK 100 } 101 102 type testSagaCommitStartTx struct{} 103 type testSagaCommitSendRes struct { 104 id gen.SagaTransactionID 105 } 106 107 func (gs *testSagaCommit1) HandleSagaDirect(process *gen.SagaProcess, ref etf.Ref, message interface{}) (interface{}, gen.DirectStatus) { 108 109 switch m := message.(type) { 110 case testSagaCommitStartTx: 111 id := process.StartTransaction(gen.SagaTransactionOptions{TwoPhaseCommit: true}, m) 112 return id, nil 113 case testSagaCommitSendRes: 114 return nil, process.SendResult(m.id, 3.14) 115 } 116 return nil, nil 117 } 118 119 func TestSagaCommitSimple(t *testing.T) { 120 121 fmt.Printf("\n=== Test GenSagaCommitSimple\n") 122 fmt.Printf("Starting node: nodeGenSagaCommitSimple01@localhost...") 123 124 node, _ := ergo.StartNode("nodeGenSagaCommitSimple01@localhost", "cookies", node.Options{}) 125 if node == nil { 126 t.Fatal("can't start node") 127 return 128 } 129 fmt.Println("OK") 130 defer node.Stop() 131 132 fmt.Printf("... Starting Saga processes: ") 133 args := argsSagaCommitArgs{ 134 workerRes: make(chan interface{}, 2), 135 sagaRes: make(chan interface{}, 2), 136 } 137 saga := &testSagaCommit1{} 138 saga_process, err := node.Spawn("saga", gen.ProcessOptions{MailboxSize: 10000}, saga, args) 139 if err != nil { 140 t.Fatal(err) 141 } 142 fmt.Println("OK") 143 144 ValueTXID, err := saga_process.Direct(testSagaCommitStartTx{}) 145 if err != nil { 146 t.Fatal(err) 147 } 148 TXID, ok := ValueTXID.(gen.SagaTransactionID) 149 if !ok { 150 t.Fatal("not a gen.SagaTransactionID") 151 } 152 fmt.Printf("... Start new TX on saga: ") 153 waitForResultWithValue(t, args.sagaRes, "newtx") 154 fmt.Printf("... Start new worker on saga: ") 155 waitForResultWithValue(t, args.workerRes, "jobresult") 156 fmt.Printf("... Sending result on saga: ") 157 if _, err := saga_process.Direct(testSagaCommitSendRes{id: TXID}); err != nil { 158 t.Fatal(err) 159 } 160 fmt.Println("OK") 161 fmt.Printf("... Handle TX done on saga: ") 162 waitForResultWithValue(t, args.sagaRes, "txdone") 163 fmt.Printf("... Handle TX commit with final value on worker: ") 164 waitForResultWithValue(t, args.workerRes, 6.28) 165 fmt.Printf("... Worker terminated: ") 166 waitForResultWithValue(t, args.workerRes, "normal") 167 } 168 169 func TestSagaCommitDistributed(t *testing.T) { 170 171 fmt.Printf("\n=== Test GenSagaCommitDistributed\n") 172 173 fmt.Printf("Starting node: nodeGenSagaCommitDist01@localhost...") 174 node1, _ := ergo.StartNode("nodeGenSagaCommitDist01@localhost", "cookies", node.Options{}) 175 if node1 == nil { 176 t.Fatal("can't start node") 177 return 178 } 179 fmt.Println("OK") 180 defer node1.Stop() 181 182 fmt.Printf("Starting node: nodeGenSagaCommitDist02@localhost...") 183 node2, _ := ergo.StartNode("nodeGenSagaCommitDist02@localhost", "cookies", node.Options{}) 184 if node2 == nil { 185 t.Fatal("can't start node") 186 return 187 } 188 fmt.Println("OK") 189 defer node2.Stop() 190 191 args1 := argsSagaCommitArgs{ 192 workerRes: make(chan interface{}, 2), 193 sagaRes: make(chan interface{}, 2), 194 testCaseDist: true, 195 } 196 fmt.Printf("... Starting Saga1 processes on node1: ") 197 saga1 := &testSagaCommit1{} 198 saga1_process, err := node1.Spawn("saga1", gen.ProcessOptions{MailboxSize: 10000}, saga1, args1) 199 if err != nil { 200 t.Fatal(err) 201 } 202 fmt.Println("OK") 203 204 args2 := argsSagaCommitArgs{ 205 workerRes: make(chan interface{}, 2), 206 sagaRes: make(chan interface{}, 2), 207 } 208 fmt.Printf("... Starting Saga2 processes on node2: ") 209 saga2 := &testSagaCommit1{} 210 saga2_process, err := node2.Spawn("saga2", gen.ProcessOptions{MailboxSize: 10000}, saga2, args2) 211 if err != nil { 212 t.Fatal(err) 213 } 214 fmt.Println("OK") 215 216 ValueTXID, err := saga1_process.Direct(testSagaCommitStartTx{}) 217 if err != nil { 218 t.Fatal(err) 219 } 220 TXID, ok := ValueTXID.(gen.SagaTransactionID) 221 if !ok { 222 t.Fatal("not a gen.SagaTransactionID") 223 } 224 fmt.Printf("... Start new TX on saga1: ") 225 waitForResultWithValue(t, args1.sagaRes, "newtx") 226 fmt.Printf("... Start new worker on saga1: ") 227 waitForResultWithValue(t, args1.workerRes, "jobresult") 228 fmt.Printf("... Start new TX on saga2: ") 229 waitForResultWithValue(t, args2.sagaRes, "newtx") 230 fmt.Printf("... Start new worker on saga2: ") 231 waitForResultWithValue(t, args2.workerRes, "jobresult") 232 fmt.Printf("... Try to send the result on saga1 (must be error ErrSagaTxInProgress): ") 233 if _, err := saga1_process.Direct(testSagaCommitSendRes{id: TXID}); err != gen.ErrSagaTxInProgress { 234 t.Fatal("must be error here") 235 } 236 fmt.Println("OK") 237 238 fmt.Printf("... Send the result on saga2 : ") 239 if _, err := saga2_process.Direct(testSagaCommitSendRes{id: TXID}); err != nil { 240 t.Fatal(err) 241 } 242 fmt.Println("OK") 243 244 fmt.Printf("... Handle TX result on saga1 (from saga2): ") 245 waitForResultWithValue(t, args1.sagaRes, "txresult") 246 fmt.Printf("... Send the result on saga1 : ") 247 if _, err := saga1_process.Direct(testSagaCommitSendRes{id: TXID}); err != nil { 248 t.Fatal(err) 249 } 250 fmt.Println("OK") 251 fmt.Printf("... Handle TX done on saga1: ") 252 waitForResultWithValue(t, args1.sagaRes, "txdone") 253 fmt.Printf("... Handle TX commit with final value on saga1 worker: ") 254 waitForResultWithValue(t, args1.workerRes, 6.28) 255 fmt.Printf("... Handle TX commit on saga2: ") 256 waitForResultWithValue(t, args2.sagaRes, 6.28) 257 fmt.Printf("... Handle TX commit with final value on saga2 worker: ") 258 waitForResultWithValue(t, args2.workerRes, 6.28) 259 }