github.com/ergo-services/ergo@v1.999.224/tests/raft_manual_test.go (about)

     1  //go:build manual
     2  // +build manual
     3  
     4  // to run this test:
     5  //   go test -run TestRaft -ergo.norecover -tags manual
     6  //
     7  // enable debug printing in the gen/raft.go
     8  //   quorum building debuging: %s/\/\/ QUODBG //
     9  //   leader election debuging: %s/\/\/ LDRDBG //
    10  //   heartbeat debuging:       %s/\/\/ HRTDBG //
    11  
    12  package tests
    13  
    14  import (
    15  	"fmt"
    16  	"math/rand"
    17  	"testing"
    18  	"time"
    19  
    20  	"github.com/ergo-services/ergo"
    21  	"github.com/ergo-services/ergo/etf"
    22  	"github.com/ergo-services/ergo/gen"
    23  	"github.com/ergo-services/ergo/node"
    24  )
    25  
    26  type testRaft struct {
    27  	gen.Raft
    28  	res chan interface{}
    29  }
    30  
    31  func (tr *testRaft) InitRaft(process *gen.RaftProcess, args ...etf.Term) (gen.RaftOptions, error) {
    32  	var options gen.RaftOptions
    33  	if len(args) > 0 {
    34  		options.Peers = args[0].([]gen.ProcessID)
    35  		options.Serial = uint64(rand.Intn(10))
    36  	}
    37  
    38  	fmt.Println(process.Self(), process.Name(), " ----------", options.Serial)
    39  	return options, gen.RaftStatusOK
    40  }
    41  
    42  func (tr *testRaft) HandleQuorum(process *gen.RaftProcess, q *gen.RaftQuorum) gen.RaftStatus {
    43  	if q == nil {
    44  		fmt.Println("QQQ quorum", process.Name(), "state: NONE")
    45  		return gen.RaftStatusOK
    46  	} else {
    47  		fmt.Println("QQQ quorum", process.Name(), "state:", q.State, q.Member, q.Peers)
    48  	}
    49  	if sent, _ := process.State.(int); sent != 1 {
    50  		process.SendAfter(process.Self(), "ok", 7*time.Second)
    51  		process.State = 1
    52  	}
    53  	//tr.res <- qs
    54  	return gen.RaftStatusOK
    55  }
    56  
    57  func (tr *testRaft) HandleLeader(process *gen.RaftProcess, leader *gen.RaftLeader) gen.RaftStatus {
    58  	fmt.Println("LLL leader", process.Name(), leader)
    59  	return gen.RaftStatusOK
    60  }
    61  
    62  func (tr *testRaft) HandleAppend(process *gen.RaftProcess, ref etf.Ref, serial uint64, key string, value etf.Term) gen.RaftStatus {
    63  	fmt.Println("AAA append", ref, serial, value)
    64  	return gen.RaftStatusOK
    65  }
    66  
    67  func (tr *testRaft) HandleGet(process *gen.RaftProcess, serial uint64) (string, etf.Term, gen.RaftStatus) {
    68  	fmt.Println("GGG get", process.Name(), serial)
    69  	return "", nil, gen.RaftStatusOK
    70  }
    71  
    72  func (tr *testRaft) HandleRaftInfo(process *gen.RaftProcess, message etf.Term) gen.ServerStatus {
    73  	q := process.Quorum()
    74  	if q == nil {
    75  		fmt.Println("III info", process.Name(), "state: NONE", "message:", message)
    76  	} else {
    77  		fmt.Println("III info", process.Name(), "Q:", q.State, q.Member, "", process.Leader(), "message:", message)
    78  	}
    79  	if l := process.Leader(); l != nil && l.Leader == process.Self() {
    80  		fmt.Println("III i'm leader. freeze", process.Self())
    81  		time.Sleep(35 * time.Second)
    82  	}
    83  	process.State = 0
    84  	return gen.ServerStatusOK
    85  }
    86  
    87  func TestRaftLeader(t *testing.T) {
    88  	fmt.Printf("\n=== Test GenRaft\n")
    89  	var N int = 4
    90  
    91  	fmt.Printf("Starting %d nodes: nodeGenRaftXX@localhost...", N)
    92  
    93  	nodes := make([]node.Node, N)
    94  	for i := range nodes {
    95  		name := fmt.Sprintf("nodeGenRaft%02d@localhost", i)
    96  		node, err := ergo.StartNode(name, "cookies", node.Options{})
    97  		if err != nil {
    98  			t.Fatal(err)
    99  		}
   100  		nodes[i] = node
   101  	}
   102  
   103  	defer func() {
   104  		for i := range nodes {
   105  			nodes[i].Stop()
   106  		}
   107  	}()
   108  	fmt.Println("OK")
   109  
   110  	rafts := make([]gen.Process, N)
   111  	results := make([]chan interface{}, N)
   112  	var args []etf.Term
   113  	var peer gen.ProcessID
   114  	for i := range rafts {
   115  		name := fmt.Sprintf("raft%02d", i+1)
   116  		if i == 0 {
   117  			args = nil
   118  		} else {
   119  			peer.Node = nodes[i-1].Name()
   120  			peer.Name = rafts[i-1].Name()
   121  			peers := []gen.ProcessID{peer}
   122  			args = []etf.Term{peers}
   123  		}
   124  		tr := &testRaft{
   125  			res: make(chan interface{}, 2),
   126  		}
   127  		results[i] = tr.res
   128  		raft, err := nodes[i].Spawn(name, gen.ProcessOptions{}, tr, args...)
   129  		if err != nil {
   130  			t.Fatal(err)
   131  		}
   132  		rafts[i] = raft
   133  		//time.Sleep(300 * time.Millisecond)
   134  	}
   135  
   136  	time.Sleep(50 * time.Second)
   137  
   138  }