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

     1  package tests
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"sync"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/ergo-services/ergo"
    11  	"github.com/ergo-services/ergo/etf"
    12  	"github.com/ergo-services/ergo/gen"
    13  	"github.com/ergo-services/ergo/lib"
    14  	"github.com/ergo-services/ergo/node"
    15  )
    16  
    17  type testServer struct {
    18  	gen.Server
    19  	res chan interface{}
    20  }
    21  
    22  func (tgs *testServer) Init(process *gen.ServerProcess, args ...etf.Term) error {
    23  	tgs.res <- nil
    24  	return nil
    25  }
    26  func (tgs *testServer) HandleCast(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
    27  	tgs.res <- message
    28  	return gen.ServerStatusOK
    29  }
    30  func (tgs *testServer) HandleCall(process *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (etf.Term, gen.ServerStatus) {
    31  	return message, gen.ServerStatusOK
    32  }
    33  func (tgs *testServer) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
    34  	tgs.res <- message
    35  	return gen.ServerStatusOK
    36  }
    37  
    38  func (tgs *testServer) HandleDirect(process *gen.ServerProcess, ref etf.Ref, message interface{}) (interface{}, gen.DirectStatus) {
    39  	switch m := message.(type) {
    40  	case makeCall:
    41  		return process.Call(m.to, m.message)
    42  	case makeCast:
    43  		return nil, process.Cast(m.to, m.message)
    44  
    45  	}
    46  	return nil, lib.ErrUnsupportedRequest
    47  }
    48  func (tgs *testServer) Terminate(process *gen.ServerProcess, reason string) {
    49  	tgs.res <- reason
    50  }
    51  
    52  type testServerDirect struct {
    53  	gen.Server
    54  	err chan error
    55  }
    56  
    57  func (tgsd *testServerDirect) Init(process *gen.ServerProcess, args ...etf.Term) error {
    58  	tgsd.err <- nil
    59  	return nil
    60  }
    61  func (tgsd *testServerDirect) HandleDirect(process *gen.ServerProcess, ref etf.Ref, message interface{}) (interface{}, gen.DirectStatus) {
    62  	switch m := message.(type) {
    63  	case asyncDirect:
    64  		m.ref = ref
    65  		process.Cast(process.Self(), m)
    66  		return nil, gen.DirectStatusIgnore
    67  	case syncDirect:
    68  		return m.val, gen.DirectStatusOK
    69  	}
    70  	return message, gen.DirectStatusOK
    71  }
    72  func (tgsd *testServerDirect) HandleCast(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
    73  	switch m := message.(type) {
    74  	case asyncDirect:
    75  		process.Reply(m.ref, m.val, nil)
    76  	}
    77  	return gen.ServerStatusOK
    78  }
    79  
    80  func TestServer(t *testing.T) {
    81  	fmt.Printf("\n=== Test Server\n")
    82  	fmt.Printf("Starting nodes: nodeGS1@localhost, nodeGS2@localhost: ")
    83  	node1, _ := ergo.StartNode("nodeGS1@localhost", "cookies", node.Options{})
    84  	node2, _ := ergo.StartNode("nodeGS2@localhost", "cookies", node.Options{})
    85  	if node1 == nil || node2 == nil {
    86  		t.Fatal("can't start nodes")
    87  	} else {
    88  		fmt.Println("OK")
    89  	}
    90  
    91  	gs1 := &testServer{
    92  		res: make(chan interface{}, 2),
    93  	}
    94  	gs2 := &testServer{
    95  		res: make(chan interface{}, 2),
    96  	}
    97  	gs3 := &testServer{
    98  		res: make(chan interface{}, 2),
    99  	}
   100  	gsDirect := &testServerDirect{
   101  		err: make(chan error, 2),
   102  	}
   103  
   104  	fmt.Printf("    wait for start of gs1 on %#v: ", node1.Name())
   105  	node1gs1, _ := node1.Spawn("gs1", gen.ProcessOptions{}, gs1, nil)
   106  	waitForResultWithValue(t, gs1.res, nil)
   107  
   108  	fmt.Printf("    wait for start of gs2 on %#v: ", node1.Name())
   109  	node1gs2, _ := node1.Spawn("gs2", gen.ProcessOptions{}, gs2, nil)
   110  	waitForResultWithValue(t, gs2.res, nil)
   111  
   112  	fmt.Printf("    wait for start of gs3 on %#v: ", node2.Name())
   113  	node2gs3, _ := node2.Spawn("gs3", gen.ProcessOptions{}, gs3, nil)
   114  	waitForResultWithValue(t, gs3.res, nil)
   115  
   116  	fmt.Printf("    wait for start of gsDirect on %#v: ", node2.Name())
   117  	node2gsDirect, _ := node2.Spawn("gsDirect", gen.ProcessOptions{}, gsDirect, nil)
   118  	waitForResult(t, gsDirect.err)
   119  
   120  	fmt.Println("Testing Server process:")
   121  
   122  	fmt.Printf("    process.Send (by Pid) local (gs1) -> local (gs2) : ")
   123  	node1gs1.Send(node1gs2.Self(), etf.Atom("hi"))
   124  	waitForResultWithValue(t, gs2.res, etf.Atom("hi"))
   125  
   126  	cast := makeCast{
   127  		to:      node1gs2.Self(),
   128  		message: etf.Atom("hi cast"),
   129  	}
   130  	node1gs1.Direct(cast)
   131  	fmt.Printf("    process.Cast (by Pid) local (gs1) -> local (gs2) : ")
   132  	waitForResultWithValue(t, gs2.res, etf.Atom("hi cast"))
   133  
   134  	fmt.Printf("    process.Call (by Pid) local (gs1) -> local (gs2): ")
   135  	v := etf.Atom("hi call")
   136  	call := makeCall{
   137  		to:      node1gs2.Self(),
   138  		message: v,
   139  	}
   140  	if v1, err := node1gs1.Direct(call); err != nil {
   141  		t.Fatal(err)
   142  	} else {
   143  		if v == v1 {
   144  			fmt.Println("OK")
   145  		} else {
   146  			e := fmt.Errorf("expected: %#v , got: %#v", v, v1)
   147  			t.Fatal(e)
   148  		}
   149  	}
   150  
   151  	fmt.Printf("    process.Send (by Name) local (gs1) -> local (gs2) : ")
   152  	node1gs1.Send(etf.Atom("gs2"), etf.Atom("hi"))
   153  	waitForResultWithValue(t, gs2.res, etf.Atom("hi"))
   154  
   155  	cast = makeCast{
   156  		to:      etf.Atom("gs2"),
   157  		message: etf.Atom("hi cast"),
   158  	}
   159  	node1gs1.Direct(cast)
   160  	fmt.Printf("    process.Cast (by Name) local (gs1) -> local (gs2) : ")
   161  	waitForResultWithValue(t, gs2.res, etf.Atom("hi cast"))
   162  
   163  	fmt.Printf("    process.Call (by Name) local (gs1) -> local (gs2): ")
   164  	call = makeCall{
   165  		to:      etf.Atom("gs2"),
   166  		message: v,
   167  	}
   168  	if v1, err := node1gs1.Direct(call); err != nil {
   169  		t.Fatal(err)
   170  	} else {
   171  		if v == v1 {
   172  			fmt.Println("OK")
   173  		} else {
   174  			e := fmt.Errorf("expected: %#v , got: %#v", v, v1)
   175  			t.Fatal(e)
   176  		}
   177  	}
   178  	alias, err := node1gs2.CreateAlias()
   179  	if err != nil {
   180  		t.Fatal(err)
   181  	}
   182  	fmt.Printf("    process.Send (by Alias) local (gs1) -> local (gs2) : ")
   183  	node1gs1.Send(alias, etf.Atom("hi"))
   184  	waitForResultWithValue(t, gs2.res, etf.Atom("hi"))
   185  
   186  	cast = makeCast{
   187  		to:      alias,
   188  		message: etf.Atom("hi cast"),
   189  	}
   190  	node1gs1.Direct(cast)
   191  	fmt.Printf("    process.Cast (by Alias) local (gs1) -> local (gs2) : ")
   192  	waitForResultWithValue(t, gs2.res, etf.Atom("hi cast"))
   193  
   194  	fmt.Printf("    process.Call (by Alias) local (gs1) -> local (gs2): ")
   195  	call = makeCall{
   196  		to:      alias,
   197  		message: v,
   198  	}
   199  	if v1, err := node1gs1.Direct(call); err != nil {
   200  		t.Fatal(err)
   201  	} else {
   202  		if v == v1 {
   203  			fmt.Println("OK")
   204  		} else {
   205  			e := fmt.Errorf("expected: %#v , got: %#v", v, v1)
   206  			t.Fatal(e)
   207  		}
   208  	}
   209  
   210  	fmt.Printf("    process.Send (by Pid) local (gs1) -> remote (gs3) : ")
   211  	node1gs1.Send(node2gs3.Self(), etf.Atom("hi"))
   212  	waitForResultWithValue(t, gs3.res, etf.Atom("hi"))
   213  
   214  	cast = makeCast{
   215  		to:      node2gs3.Self(),
   216  		message: etf.Atom("hi cast"),
   217  	}
   218  	node1gs1.Direct(cast)
   219  	fmt.Printf("    process.Cast (by Pid) local (gs1) -> remote (gs3) : ")
   220  	waitForResultWithValue(t, gs3.res, etf.Atom("hi cast"))
   221  
   222  	fmt.Printf("    process.Call (by Pid) local (gs1) -> remote (gs3): ")
   223  	call = makeCall{
   224  		to:      node2gs3.Self(),
   225  		message: v,
   226  	}
   227  	if v1, err := node1gs1.Direct(call); err != nil {
   228  		t.Fatal(err)
   229  	} else {
   230  		if v == v1 {
   231  			fmt.Println("OK")
   232  		} else {
   233  			e := fmt.Errorf("expected: %#v , got: %#v", v, v1)
   234  			t.Fatal(e)
   235  		}
   236  	}
   237  
   238  	fmt.Printf("    process.Send (by Name) local (gs1) -> remote (gs3) : ")
   239  	processName := gen.ProcessID{Name: "gs3", Node: node2.Name()}
   240  	node1gs1.Send(processName, etf.Atom("hi"))
   241  	waitForResultWithValue(t, gs3.res, etf.Atom("hi"))
   242  
   243  	cast = makeCast{
   244  		to:      processName,
   245  		message: etf.Atom("hi cast"),
   246  	}
   247  	node1gs1.Direct(cast)
   248  	fmt.Printf("    process.Cast (by Name) local (gs1) -> remote (gs3) : ")
   249  	waitForResultWithValue(t, gs3.res, etf.Atom("hi cast"))
   250  
   251  	fmt.Printf("    process.Call (by Name) local (gs1) -> remote (gs3): ")
   252  	call = makeCall{
   253  		to:      processName,
   254  		message: v,
   255  	}
   256  	if v1, err := node1gs1.Direct(call); err != nil {
   257  		t.Fatal(err)
   258  	} else {
   259  		if v == v1 {
   260  			fmt.Println("OK")
   261  		} else {
   262  			e := fmt.Errorf("expected: %#v , got: %#v", v, v1)
   263  			t.Fatal(e)
   264  		}
   265  	}
   266  
   267  	fmt.Printf("    process.Send (by Alias) local (gs1) -> remote (gs3) : ")
   268  	alias, err = node2gs3.CreateAlias()
   269  	if err != nil {
   270  		t.Fatal(err)
   271  	}
   272  
   273  	node1gs1.Send(alias, etf.Atom("hi"))
   274  	waitForResultWithValue(t, gs3.res, etf.Atom("hi"))
   275  
   276  	cast = makeCast{
   277  		to:      alias,
   278  		message: etf.Atom("hi cast"),
   279  	}
   280  	node1gs1.Direct(cast)
   281  	fmt.Printf("    process.Cast (by Alias) local (gs1) -> remote (gs3) : ")
   282  	waitForResultWithValue(t, gs3.res, etf.Atom("hi cast"))
   283  
   284  	fmt.Printf("    process.Call (by Alias) local (gs1) -> remote (gs3): ")
   285  	call = makeCall{
   286  		to:      alias,
   287  		message: v,
   288  	}
   289  	if v1, err := node1gs1.Direct(call); err != nil {
   290  		t.Fatal(err)
   291  	} else {
   292  		if v == v1 {
   293  			fmt.Println("OK")
   294  		} else {
   295  			e := fmt.Errorf("expected: %#v , got: %#v", v, v1)
   296  			t.Fatal(e)
   297  		}
   298  	}
   299  
   300  	fmt.Printf("    process.Direct (without HandleDirect implementation): ")
   301  	if _, err := node1gs1.Direct(nil); err != lib.ErrUnsupportedRequest {
   302  		t.Fatal("must be ErrUnsupportedRequest")
   303  	} else {
   304  		fmt.Println("OK")
   305  	}
   306  	fmt.Printf("    process.Direct (with HandleDirect implementation): ")
   307  	if v1, err := node2gsDirect.Direct(v); err != nil {
   308  		t.Fatal(err)
   309  	} else {
   310  		if v == v1 {
   311  			fmt.Println("OK")
   312  		} else {
   313  			e := fmt.Errorf("expected: %#v , got: %#v", v, v1)
   314  			t.Fatal(e)
   315  		}
   316  	}
   317  	fmt.Printf("    process.Direct (with HandleDirect implementation with async reply): ")
   318  
   319  	av := etf.Atom("async direct")
   320  	if v1, err := node2gsDirect.Direct(asyncDirect{val: av}); err != nil {
   321  		t.Fatal(err)
   322  	} else {
   323  		if av == v1 {
   324  			fmt.Println("OK")
   325  		} else {
   326  			e := fmt.Errorf("expected: %#v , got: %#v", av, v1)
   327  			t.Fatal(e)
   328  		}
   329  	}
   330  
   331  	fmt.Printf("    process.SetTrapExit(true) and call process.Exit() gs2: ")
   332  	node1gs2.SetTrapExit(true)
   333  	node1gs2.Exit("test trap")
   334  	waitForResultWithValue(t, gs2.res, gen.MessageExit{Pid: node1gs2.Self(), Reason: "test trap"})
   335  	fmt.Printf("    check process.IsAlive gs2 (must be alive): ")
   336  	if !node1gs2.IsAlive() {
   337  		t.Fatal("should be alive")
   338  	}
   339  	fmt.Println("OK")
   340  
   341  	fmt.Printf("    process.SetTrapExit(false) and call process.Exit() gs2: ")
   342  	node1gs2.SetTrapExit(false)
   343  	node1gs2.Exit("test trap")
   344  	waitForResultWithValue(t, gs2.res, "test trap")
   345  
   346  	fmt.Printf("    check process.IsAlive gs2 (must be died): ")
   347  	if node1gs2.IsAlive() {
   348  		t.Fatal("shouldn't be alive")
   349  	}
   350  	fmt.Println("OK")
   351  
   352  	fmt.Printf("Stopping nodes: %v, %v\n", node1.Name(), node2.Name())
   353  	node1.Stop()
   354  	node2.Stop()
   355  }
   356  func TestServerDirect(t *testing.T) {
   357  	fmt.Printf("\n=== Test Server Direct\n")
   358  	fmt.Printf("Starting node: nodeGS1Direct@localhost: ")
   359  	node1, _ := ergo.StartNode("nodeGS1Direct@localhost", "cookies", node.Options{})
   360  	if node1 == nil {
   361  		t.Fatal("can't start nodes")
   362  	} else {
   363  		fmt.Println("OK")
   364  	}
   365  	defer node1.Stop()
   366  
   367  	gsDirect := &testServerDirect{
   368  		err: make(chan error, 2),
   369  	}
   370  
   371  	fmt.Printf("    wait for start of gsDirect on %#v: ", node1.Name())
   372  	node1gsDirect, _ := node1.Spawn("gsDirect", gen.ProcessOptions{}, gsDirect, nil)
   373  	waitForResult(t, gsDirect.err)
   374  
   375  	var wg sync.WaitGroup
   376  
   377  	fmt.Println("   process.Direct with 1000 goroutines:")
   378  	direct := func() {
   379  		v := etf.Atom("sync direct")
   380  		defer wg.Done()
   381  	repeat:
   382  		if v1, err := node1gsDirect.Direct(syncDirect{val: v}); err != nil {
   383  			if err == lib.ErrProcessBusy {
   384  				goto repeat
   385  			}
   386  			t.Fatal(err)
   387  		} else {
   388  			if v != v1 {
   389  				e := fmt.Errorf("expected: %#v , got: %#v", v, v1)
   390  				t.Fatal(e)
   391  			}
   392  		}
   393  	}
   394  	n := 1000
   395  	for i := 0; i < n; i++ {
   396  		wg.Add(1)
   397  		go direct()
   398  	}
   399  
   400  	wg.Wait()
   401  	fmt.Println("OK")
   402  }
   403  
   404  type messageOrderGS struct {
   405  	gen.Server
   406  	n   int
   407  	res chan interface{}
   408  }
   409  
   410  type testCase1 struct {
   411  	n int
   412  }
   413  
   414  type testCase2 struct {
   415  	n int
   416  }
   417  type testCase3 struct {
   418  	n int
   419  }
   420  
   421  func (gs *messageOrderGS) Init(process *gen.ServerProcess, args ...etf.Term) error {
   422  	gs.res <- nil
   423  	return nil
   424  }
   425  
   426  func (gs *messageOrderGS) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
   427  	switch m := message.(type) {
   428  	case testCase1:
   429  		if gs.n+1 != m.n {
   430  			panic(fmt.Sprintf("Disordered messages on %d (awaited: %d)", m.n, gs.n+1))
   431  		}
   432  		gs.n = m.n
   433  
   434  		if gs.n == 100 {
   435  			gs.res <- 1000
   436  		}
   437  		return gen.ServerStatusOK
   438  
   439  	case testCase2:
   440  		if gs.n != m.n {
   441  			panic(fmt.Sprintf("Disordered messages on %d (awaited: %d)", m.n, gs.n+1))
   442  		}
   443  		gs.n = m.n - 1
   444  		value, err := process.Call("gs3order", message)
   445  		if err != nil {
   446  			panic(err)
   447  		}
   448  		if value.(string) != "ok" {
   449  			panic("wrong result")
   450  		}
   451  
   452  		if gs.n == 0 {
   453  			gs.res <- 123
   454  		}
   455  		return gen.ServerStatusOK
   456  	}
   457  
   458  	return gen.ServerStatusStop
   459  }
   460  
   461  func (gs *messageOrderGS) HandleCall(process *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (etf.Term, gen.ServerStatus) {
   462  	switch message.(type) {
   463  	case testCase2:
   464  		return "ok", gen.ServerStatusOK
   465  	case testCase3:
   466  		return "ok", gen.ServerStatusOK
   467  	}
   468  	return nil, fmt.Errorf("incorrect call")
   469  }
   470  
   471  func (gs *messageOrderGS) HandleDirect(process *gen.ServerProcess, ref etf.Ref, message interface{}) (interface{}, gen.DirectStatus) {
   472  	switch m := message.(type) {
   473  	case testCase3:
   474  		for i := 0; i < m.n; i++ {
   475  			value, err := process.Call("gs3order", message)
   476  			if err != nil {
   477  				panic(err)
   478  			}
   479  			if value.(string) != "ok" {
   480  				panic("wrong result")
   481  			}
   482  		}
   483  		return nil, gen.DirectStatusOK
   484  
   485  	}
   486  	return nil, fmt.Errorf("incorrect direct call")
   487  }
   488  
   489  type GSCallPanic struct {
   490  	gen.Server
   491  }
   492  
   493  func (gs *GSCallPanic) Init(process *gen.ServerProcess, args ...etf.Term) error {
   494  	return nil
   495  }
   496  
   497  func (gs *GSCallPanic) HandleCall(process *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (etf.Term, gen.ServerStatus) {
   498  	m := message.(string)
   499  	if m == "panic" {
   500  		panic("test")
   501  	}
   502  
   503  	return "ok", gen.ServerStatusOK
   504  }
   505  
   506  func (gs *GSCallPanic) HandleDirect(process *gen.ServerProcess, ref etf.Ref, message interface{}) (interface{}, gen.DirectStatus) {
   507  
   508  	pids, ok := message.([]etf.Pid)
   509  	if !ok {
   510  		return nil, fmt.Errorf("not a pid")
   511  	}
   512  	fmt.Printf("    making a call p1node1 -> p1node2 (panic): ")
   513  	if _, err := process.CallWithTimeout(pids[0], "panic", 1); err == nil {
   514  		return nil, fmt.Errorf("must be error here")
   515  	} else {
   516  		fmt.Println("OK")
   517  	}
   518  	fmt.Printf("    making a call p1node1 -> p2node2: ")
   519  	v, err := process.Call(pids[1], "test")
   520  	if err != nil {
   521  		return nil, err
   522  	}
   523  	if v.(string) != "ok" {
   524  		return nil, fmt.Errorf("wrong result %#v", v)
   525  	}
   526  	fmt.Println("OK")
   527  
   528  	return nil, gen.DirectStatusOK
   529  }
   530  
   531  func TestServerCallServerWithPanic(t *testing.T) {
   532  	fmt.Printf("\n=== Test Server. Making a Call to Server with panic (issue 86) \n")
   533  	fmt.Printf("Starting node: nodeGSCallWithPanic1@localhost: ")
   534  	node1, err1 := ergo.StartNode("nodeGSCallWithPanic1@localhost", "cookies", node.Options{})
   535  	if err1 != nil {
   536  		t.Fatal("can't start node", err1)
   537  	} else {
   538  		fmt.Println("OK")
   539  	}
   540  	fmt.Printf("Starting node: nodeGSCallWithPanic2@localhost: ")
   541  	node2, err2 := ergo.StartNode("nodeGSCallWithPanic2@localhost", "cookies", node.Options{})
   542  	if err2 != nil {
   543  		t.Fatal("can't start node", err2)
   544  	} else {
   545  		fmt.Println("OK")
   546  	}
   547  
   548  	p1n1, err := node1.Spawn("p1node1", gen.ProcessOptions{}, &GSCallPanic{})
   549  	if err != nil {
   550  		t.Fatal(err)
   551  	}
   552  	p1n2, err := node2.Spawn("p1node2", gen.ProcessOptions{}, &GSCallPanic{})
   553  	if err != nil {
   554  		t.Fatal(err)
   555  	}
   556  	p2n2, err := node2.Spawn("2node2", gen.ProcessOptions{}, &GSCallPanic{})
   557  	if err != nil {
   558  		t.Fatal(err)
   559  	}
   560  
   561  	pids := []etf.Pid{p1n2.Self(), p2n2.Self()}
   562  
   563  	if _, err := p1n1.Direct(pids); err != nil {
   564  		t.Fatal(err)
   565  	}
   566  }
   567  
   568  func TestServerMessageOrder(t *testing.T) {
   569  	fmt.Printf("\n=== Test Server message order\n")
   570  	fmt.Printf("Starting node: nodeGS1MessageOrder@localhost: ")
   571  	node1, _ := ergo.StartNode("nodeGS1MessageOrder@localhost", "cookies", node.Options{})
   572  	if node1 == nil {
   573  		t.Fatal("can't start nodes")
   574  	} else {
   575  		fmt.Println("OK")
   576  	}
   577  
   578  	gs1 := &messageOrderGS{
   579  		res: make(chan interface{}, 2),
   580  	}
   581  
   582  	gs2 := &messageOrderGS{
   583  		res: make(chan interface{}, 2),
   584  	}
   585  
   586  	gs3 := &messageOrderGS{
   587  		res: make(chan interface{}, 2),
   588  	}
   589  
   590  	fmt.Printf("    wait for start of gs1order on %#v: ", node1.Name())
   591  	node1gs1, err1 := node1.Spawn("gs1order", gen.ProcessOptions{}, gs1, nil)
   592  	if err1 != nil {
   593  		panic(err1)
   594  	}
   595  	waitForResultWithValue(t, gs1.res, nil)
   596  
   597  	fmt.Printf("    wait for start of gs2order on %#v: ", node1.Name())
   598  	node1gs2, err2 := node1.Spawn("gs2order", gen.ProcessOptions{}, gs2, nil)
   599  	if err2 != nil {
   600  		panic(err2)
   601  	}
   602  	waitForResultWithValue(t, gs2.res, nil)
   603  
   604  	fmt.Printf("    wait for start of gs3order on %#v: ", node1.Name())
   605  	node1gs3, err3 := node1.Spawn("gs3order", gen.ProcessOptions{}, gs3, nil)
   606  	if err3 != nil {
   607  		panic(err3)
   608  	}
   609  	waitForResultWithValue(t, gs3.res, nil)
   610  
   611  	fmt.Printf("    sending 100 messages from gs1 to gs2. checking the order: ")
   612  	for i := 1; i < 101; i++ {
   613  		err := node1gs1.Send(node1gs2.Self(), testCase1{n: i})
   614  		if err != nil {
   615  			t.Fatal(err)
   616  		}
   617  	}
   618  	waitForResultWithValue(t, gs2.res, 1000)
   619  
   620  	fmt.Printf("    making Direct call with making a call from gs2 to gs3 1 time: ")
   621  	_, err := node1gs2.Direct(testCase3{n: 1})
   622  	if err != nil {
   623  		t.Fatal(err)
   624  	}
   625  	fmt.Println("OK")
   626  	fmt.Printf("    making Direct call with making a call from gs2 to gs3 100 times: ")
   627  	_, err = node1gs2.Direct(testCase3{n: 100})
   628  	if err != nil {
   629  		t.Fatal(err)
   630  	}
   631  	fmt.Println("OK")
   632  
   633  	gs2.n = 100
   634  
   635  	fmt.Printf("    sending 100 messages from gs1 to gs2 with making a call from gs2 to gs3: ")
   636  	for i := gs2.n; i > 0; i-- {
   637  		err := node1gs1.Send(node1gs2.Self(), testCase2{n: i})
   638  		if err != nil {
   639  			t.Fatal(err)
   640  		}
   641  	}
   642  	waitForResultWithValue(t, gs2.res, 123)
   643  	node1gs3.Exit("normal")
   644  	node1.Stop()
   645  	node1.Wait()
   646  }
   647  
   648  type messageFloodSourceGS struct {
   649  	gen.Server
   650  	id  int
   651  	res chan interface{}
   652  }
   653  
   654  type messageFlood struct {
   655  	id int
   656  	i  int
   657  }
   658  
   659  func (fl *messageFloodSourceGS) Init(process *gen.ServerProcess, args ...etf.Term) error {
   660  	fl.res <- nil
   661  	return nil
   662  }
   663  
   664  func (fl *messageFloodSourceGS) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
   665  	max := message.(int)
   666  
   667  	for i := 1; i < max+1; i++ {
   668  		if err := process.Send("gsdest", messageFlood{id: fl.id - 1, i: i}); err != nil {
   669  			panic(fmt.Sprintf("err on making a send: %s", err))
   670  		}
   671  		if err := process.Cast("gsdest", messageFlood{id: fl.id - 1, i: i}); err != nil {
   672  			panic(fmt.Sprintf("err on making a cast: %s", err))
   673  		}
   674  		if _, err := process.Call("gsdest", messageFlood{id: fl.id - 1, i: i}); err != nil {
   675  			panic(fmt.Sprintf("err on making a call: %s", err))
   676  		}
   677  
   678  	}
   679  
   680  	return gen.ServerStatusStop
   681  }
   682  
   683  type messageFloodDestGS struct {
   684  	gen.Server
   685  	max  int
   686  	info [5]int
   687  	cast [5]int
   688  	call [5]int
   689  	done int
   690  	res  chan interface{}
   691  }
   692  
   693  func (fl *messageFloodDestGS) Init(process *gen.ServerProcess, args ...etf.Term) error {
   694  
   695  	fl.res <- nil
   696  	return nil
   697  }
   698  
   699  func (fl *messageFloodDestGS) HandleCall(process *gen.ServerProcess, from gen.ServerFrom, message etf.Term) (etf.Term, gen.ServerStatus) {
   700  	switch m := message.(type) {
   701  	case messageFlood:
   702  		if fl.call[m.id]+1 != m.i {
   703  			panic("wrong order")
   704  		}
   705  		fl.call[m.id] = m.i
   706  		if fl.call[m.id] == fl.max {
   707  			fl.done++
   708  		}
   709  		if fl.done != len(fl.info)*3 {
   710  			return nil, gen.ServerStatusOK
   711  		}
   712  	default:
   713  		return nil, gen.ServerStatusStop
   714  	}
   715  
   716  	fl.res <- nil
   717  	return nil, gen.ServerStatusOK
   718  }
   719  
   720  func (fl *messageFloodDestGS) HandleCast(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
   721  	switch m := message.(type) {
   722  	case messageFlood:
   723  		if fl.cast[m.id]+1 != m.i {
   724  			panic("wrong order")
   725  		}
   726  		fl.cast[m.id] = m.i
   727  		if fl.cast[m.id] == fl.max {
   728  			fl.done++
   729  		}
   730  		if fl.done != len(fl.info)*3 {
   731  			return gen.ServerStatusOK
   732  		}
   733  	default:
   734  		return gen.ServerStatusStop
   735  	}
   736  
   737  	fl.res <- nil
   738  	return gen.ServerStatusOK
   739  }
   740  
   741  func (fl *messageFloodDestGS) HandleInfo(process *gen.ServerProcess, message etf.Term) gen.ServerStatus {
   742  	switch m := message.(type) {
   743  	case messageFlood:
   744  		if fl.info[m.id]+1 != m.i {
   745  			panic("wrong order")
   746  		}
   747  		fl.info[m.id] = m.i
   748  		if fl.info[m.id] == fl.max {
   749  			fl.done++
   750  		}
   751  		if fl.done != len(fl.info)*3 {
   752  			return gen.ServerStatusOK
   753  		}
   754  	default:
   755  		return gen.ServerStatusStop
   756  	}
   757  
   758  	fl.res <- nil
   759  	return gen.ServerStatusOK
   760  }
   761  
   762  type testCaseFlood struct {
   763  	id int
   764  }
   765  
   766  func TestServerMessageFlood(t *testing.T) {
   767  	fmt.Printf("\n=== Test Server message flood \n")
   768  	fmt.Printf("Starting node: nodeGS1MessageFlood@localhost: ")
   769  	node1, _ := ergo.StartNode("nodeGS1MessageFlood@localhost", "cookies", node.Options{})
   770  	if node1 == nil {
   771  		t.Fatal("can't start nodes")
   772  	} else {
   773  		fmt.Println("OK")
   774  	}
   775  
   776  	gs1source := &messageFloodSourceGS{
   777  		id:  1,
   778  		res: make(chan interface{}, 2),
   779  	}
   780  	gs2source := &messageFloodSourceGS{
   781  		id:  2,
   782  		res: make(chan interface{}, 2),
   783  	}
   784  	gs3source := &messageFloodSourceGS{
   785  		id:  3,
   786  		res: make(chan interface{}, 2),
   787  	}
   788  	gs4source := &messageFloodSourceGS{
   789  		id:  4,
   790  		res: make(chan interface{}, 2),
   791  	}
   792  	gs5source := &messageFloodSourceGS{
   793  		id:  5,
   794  		res: make(chan interface{}, 2),
   795  	}
   796  
   797  	gsdest := &messageFloodDestGS{
   798  		res: make(chan interface{}, 2),
   799  	}
   800  	fmt.Printf("    wait for start of gs1source on %#v: ", node1.Name())
   801  	gs1sourceProcess, _ := node1.Spawn("gs1source", gen.ProcessOptions{}, gs1source, nil)
   802  	waitForResultWithValue(t, gs1source.res, nil)
   803  
   804  	fmt.Printf("    wait for start of gs2source on %#v: ", node1.Name())
   805  	gs2sourceProcess, _ := node1.Spawn("gs2source", gen.ProcessOptions{}, gs2source, nil)
   806  	waitForResultWithValue(t, gs2source.res, nil)
   807  
   808  	fmt.Printf("    wait for start of gs3source on %#v: ", node1.Name())
   809  	gs3sourceProcess, _ := node1.Spawn("gs3source", gen.ProcessOptions{}, gs3source, nil)
   810  	waitForResultWithValue(t, gs3source.res, nil)
   811  
   812  	fmt.Printf("    wait for start of gs4source on %#v: ", node1.Name())
   813  	gs4sourceProcess, _ := node1.Spawn("gs4source", gen.ProcessOptions{}, gs4source, nil)
   814  	waitForResultWithValue(t, gs4source.res, nil)
   815  
   816  	fmt.Printf("    wait for start of gs5source on %#v: ", node1.Name())
   817  	gs5sourceProcess, _ := node1.Spawn("gs5source", gen.ProcessOptions{}, gs5source, nil)
   818  	waitForResultWithValue(t, gs5source.res, nil)
   819  
   820  	fmt.Printf("    wait for start of gsdest on %#v: ", node1.Name())
   821  	node1.Spawn("gsdest", gen.ProcessOptions{}, gsdest, nil)
   822  	waitForResultWithValue(t, gsdest.res, nil)
   823  
   824  	gsdest.max = 1000
   825  	// start flood
   826  	gs1sourceProcess.Send(gs1sourceProcess.Self(), gsdest.max)
   827  	gs2sourceProcess.Send(gs2sourceProcess.Self(), gsdest.max)
   828  	gs3sourceProcess.Send(gs3sourceProcess.Self(), gsdest.max)
   829  	gs4sourceProcess.Send(gs4sourceProcess.Self(), gsdest.max)
   830  	gs5sourceProcess.Send(gs5sourceProcess.Self(), gsdest.max)
   831  
   832  	waitForResultWithValue(t, gsdest.res, nil)
   833  }
   834  
   835  func waitForResult(t *testing.T, w chan error) {
   836  	select {
   837  	case e := <-w:
   838  		if e == nil {
   839  			fmt.Println("OK")
   840  			return
   841  		}
   842  
   843  		t.Fatal(e)
   844  
   845  	case <-time.After(time.Second * time.Duration(1)):
   846  		t.Fatal("result timeout")
   847  	}
   848  }
   849  
   850  func waitForResultWithMultiValue(t *testing.T, w chan interface{}, values etf.List) {
   851  
   852  	select {
   853  	case v := <-w:
   854  		found := false
   855  		i := 0
   856  		for {
   857  			if reflect.DeepEqual(v, values[i]) {
   858  				found = true
   859  				values[i] = values[0]
   860  				values = values[1:]
   861  				if len(values) == 0 {
   862  					return
   863  				}
   864  				// i dont care about stack growing since 'values'
   865  				// usually short
   866  				waitForResultWithMultiValue(t, w, values)
   867  				break
   868  			}
   869  			i++
   870  			if i+1 > len(values) {
   871  				break
   872  			}
   873  		}
   874  
   875  		if !found {
   876  			e := fmt.Errorf("got unexpected value: %#v", v)
   877  			t.Fatal(e)
   878  		}
   879  
   880  	case <-time.After(time.Second * time.Duration(2)):
   881  		t.Fatal("result timeout")
   882  	}
   883  	fmt.Println("OK")
   884  }
   885  
   886  func waitForResultWithValue(t *testing.T, w chan interface{}, value interface{}) {
   887  	select {
   888  	case v := <-w:
   889  		if reflect.DeepEqual(v, value) {
   890  			fmt.Println("OK")
   891  		} else {
   892  			e := fmt.Errorf("expected: %#v , got: %#v", value, v)
   893  			t.Fatal(e)
   894  		}
   895  
   896  	case <-time.After(time.Second * time.Duration(2)):
   897  		t.Fatal("result timeout")
   898  	}
   899  }
   900  
   901  func waitForResultWithValueReturnError(t *testing.T, w chan interface{}, value interface{}) error {
   902  	select {
   903  	case v := <-w:
   904  		if reflect.DeepEqual(v, value) {
   905  			return nil
   906  		} else {
   907  			return fmt.Errorf("expected: %#v , got: %#v", value, v)
   908  		}
   909  
   910  	case <-time.After(time.Second * time.Duration(2)):
   911  		return fmt.Errorf("result timeout")
   912  	}
   913  }
   914  
   915  func waitForResultWithValueOrValue(t *testing.T, w chan interface{}, value1, value2 interface{}) {
   916  	select {
   917  	case v := <-w:
   918  		if reflect.DeepEqual(v, value1) {
   919  			fmt.Println("OK")
   920  		} else {
   921  			if reflect.DeepEqual(v, value2) {
   922  				fmt.Println("OK")
   923  			} else {
   924  				e := fmt.Errorf("expected another value, but got: %#v", v)
   925  				t.Fatal(e)
   926  			}
   927  		}
   928  
   929  	case <-time.After(time.Second * time.Duration(2)):
   930  		t.Fatal("result timeout")
   931  	}
   932  }
   933  
   934  func waitForTimeout(t *testing.T, w chan interface{}) {
   935  	select {
   936  	case v := <-w:
   937  		e := fmt.Errorf("got value we shouldn't receive: %#v", v)
   938  		t.Fatal(e)
   939  
   940  	case <-time.After(time.Millisecond * time.Duration(300)):
   941  		return
   942  	}
   943  }