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  }