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

     1  package tests
     2  
     3  // - Supervisor
     4  
     5  // - rest for one (permanent)
     6  //    start node1
     7  //    start supevisor sv1 with genservers gs1,gs2,gs3
     8  //    gs1.stop(normal) (sv1 stoping gs1)
     9  //                     (sv1 stoping gs2,gs3)
    10  //                     (sv1 starting gs1,gs2,gs3)
    11  //    gs2.stop(shutdown) (sv1 stoping gs2)
    12  //                     (sv1 stoping gs1,gs3)
    13  //                     (sv1 starting gs1,gs2,gs3)
    14  //    gs3.stop(panic) (sv1 stoping gs3)
    15  //                     (sv1 stoping gs1,gs2)
    16  //                     (sv1 starting gs1,gs2,gs3)
    17  //
    18  // - rest for one (transient)
    19  //    start node1
    20  //    start supevisor sv1 with genservers gs1,gs2,gs3
    21  //    gs3.stop(panic) (sv1 stoping gs3)
    22  //                     (sv1 stopping gs1, gs2)
    23  //                     (sv1 starting gs1, gs2, gs3)
    24  
    25  //    gs1.stop(normal) (sv1 stoping gs1)
    26  //                     ( gs2, gs3 - still working)
    27  //    gs2.stop(shutdown) (sv1 stoping gs2)
    28  //                     (gs3 - still working)
    29  //
    30  // - rest for one (temoporary)
    31  //   start node1
    32  //    start supevisor sv1 with genservers gs1,gs2,gs3
    33  
    34  //    gs3.stop(panic) (sv1 stoping gs3)
    35  //                     (sv1 stopping gs1, gs2)
    36  
    37  //    start again gs1, gs2, gs3 via sv1
    38  //    gs1.stop(normal) (sv1 stopping gs1)
    39  //                     (gs2, gs3 are still running)
    40  //    gs2.stop(shutdown) (sv1 stopping gs2)
    41  //                     (gs3 are still running)
    42  
    43  import (
    44  	"fmt"
    45  	"testing"
    46  
    47  	"github.com/ergo-services/ergo"
    48  	"github.com/ergo-services/ergo/etf"
    49  	"github.com/ergo-services/ergo/gen"
    50  	"github.com/ergo-services/ergo/node"
    51  	// "time"
    52  	// "github.com/ergo-services/ergo/etf"
    53  )
    54  
    55  type testSupervisorRestForOne struct {
    56  	gen.Supervisor
    57  	ch chan interface{}
    58  }
    59  
    60  func TestSupervisorRestForOne(t *testing.T) {
    61  	var err error
    62  	fmt.Printf("\n=== Test Supervisor - rest for one\n")
    63  	fmt.Printf("Starting node nodeSvRestForOne@localhost: ")
    64  	node1, _ := ergo.StartNode("nodeSvRestForOne@localhost", "cookies", node.Options{})
    65  	if node1 == nil {
    66  		t.Fatal("can't start node")
    67  	} else {
    68  		fmt.Println("OK")
    69  	}
    70  
    71  	// ===================================================================================================
    72  	// test SupervisorStrategyRestartPermanent
    73  	fmt.Printf("Starting supervisor 'testSupervisorPermanent' (%s)... ", gen.SupervisorStrategyRestartPermanent)
    74  	sv := &testSupervisorRestForOne{
    75  		ch: make(chan interface{}, 10),
    76  	}
    77  	processSV, err := node1.Spawn("testSupervisorPermanent", gen.ProcessOptions{}, sv, gen.SupervisorStrategyRestartPermanent, sv.ch)
    78  	if err != nil {
    79  		t.Fatal(err)
    80  	}
    81  	children := make([]etf.Pid, 3)
    82  
    83  	children, err = waitNeventsSupervisorChildren(sv.ch, 3, children)
    84  	if err != nil {
    85  		t.Fatal(err)
    86  	} else {
    87  		fmt.Println("OK")
    88  	}
    89  
    90  	// testing permanent
    91  	testCases := []ChildrenTestCase{
    92  		{
    93  			reason:   "normal",
    94  			statuses: []string{"new", "new", "new"},
    95  			events:   6, // waiting for 3 terminates and 3 starts
    96  		},
    97  		{
    98  			reason:   "abnormal",
    99  			statuses: []string{"old", "new", "new"},
   100  			events:   4, // waiting for 2 terminates and 2 starts
   101  		},
   102  		{
   103  			reason:   "shutdown",
   104  			statuses: []string{"old", "old", "new"},
   105  			events:   2, // waiting for 1 terminates and 1 starts
   106  		},
   107  	}
   108  	for i := range children {
   109  		fmt.Printf("... stopping child %d with '%s' reason and waiting for restarting rest of them ... ", i+1, testCases[i].reason)
   110  		processSV.Send(children[i], testCases[i].reason) // stopping child
   111  
   112  		if children1, err := waitNeventsSupervisorChildren(sv.ch, testCases[i].events, children); err != nil {
   113  			t.Fatal(err)
   114  		} else {
   115  			if checkExpectedChildrenStatus(children[:], children1[:], testCases[i].statuses) {
   116  				fmt.Println("OK")
   117  				children = children1
   118  			} else {
   119  				e := fmt.Errorf("got something else except we expected (%v). old: %v new: %v", testCases[i].statuses, children, children1)
   120  				t.Fatal(e)
   121  			}
   122  		}
   123  	}
   124  
   125  	fmt.Printf("Stopping supervisor 'testSupervisorPermanent' (%s)... ", gen.SupervisorStrategyRestartPermanent)
   126  	processSV.Exit("x")
   127  	if children1, err := waitNeventsSupervisorChildren(sv.ch, 3, children); err != nil {
   128  		t.Fatal(err)
   129  	} else {
   130  		statuses := []string{"empty", "empty", "empty"}
   131  		if checkExpectedChildrenStatus(children[:], children1[:], statuses) {
   132  			fmt.Println("OK")
   133  			children = children1
   134  		} else {
   135  			e := fmt.Errorf("got something else except we expected (%v). old: %v new: %v", statuses, children, children1)
   136  			t.Fatal(e)
   137  		}
   138  	}
   139  
   140  	// ===================================================================================================
   141  	// test SupervisorStrategyRestartTransient
   142  	fmt.Printf("Starting supervisor 'testSupervisorTransient' (%s)... ", gen.SupervisorStrategyRestartTransient)
   143  	sv = &testSupervisorRestForOne{
   144  		ch: make(chan interface{}, 10),
   145  	}
   146  	processSV, err = node1.Spawn("testSupervisorTransient", gen.ProcessOptions{}, sv, gen.SupervisorStrategyRestartTransient, sv.ch)
   147  	if err != nil {
   148  		t.Fatal(err)
   149  	}
   150  	children = make([]etf.Pid, 3)
   151  
   152  	children, err = waitNeventsSupervisorChildren(sv.ch, 3, children)
   153  	if err != nil {
   154  		t.Fatal(err)
   155  	} else {
   156  		fmt.Println("OK")
   157  	}
   158  
   159  	// testing transient
   160  	testCases = []ChildrenTestCase{
   161  		{
   162  			reason:   "abnormal",
   163  			statuses: []string{"new", "new", "new"},
   164  			events:   6, // waiting for 3 terminates and 3 starts
   165  		},
   166  		{
   167  			reason:   "normal",
   168  			statuses: []string{"old", "empty", "old"},
   169  			events:   1, // waiting for 1 terminate
   170  		},
   171  		{
   172  			reason:   "shutdown",
   173  			statuses: []string{"old", "empty", "empty"},
   174  			events:   1, // waiting for 1 terminates
   175  		},
   176  	}
   177  	for i := range children {
   178  		fmt.Printf("... stopping child %d with '%s' reason and waiting for restarting if reason != normal ... ", i+1, testCases[i].reason)
   179  		processSV.Send(children[i], testCases[i].reason) // stopping child
   180  
   181  		if children1, err := waitNeventsSupervisorChildren(sv.ch, testCases[i].events, children); err != nil {
   182  			t.Fatal(err)
   183  		} else {
   184  			if checkExpectedChildrenStatus(children[:], children1[:], testCases[i].statuses) {
   185  				fmt.Println("OK")
   186  				children = children1
   187  			} else {
   188  				e := fmt.Errorf("got something else except we expected (%v). old: %v new: %v", testCases[i].statuses, children, children1)
   189  				t.Fatal(e)
   190  			}
   191  		}
   192  	}
   193  
   194  	fmt.Printf("Stopping supervisor 'testSupervisorTransient' (%s)... ", gen.SupervisorStrategyRestartTransient)
   195  	processSV.Exit("x")
   196  	if children1, err := waitNeventsSupervisorChildren(sv.ch, 1, children); err != nil {
   197  		t.Fatal(err)
   198  	} else {
   199  		statuses := []string{"empty", "empty", "empty"}
   200  		if checkExpectedChildrenStatus(children[:], children1[:], statuses) {
   201  			fmt.Println("OK")
   202  			children = children1
   203  		} else {
   204  			e := fmt.Errorf("got something else except we expected (%v). old: %v new: %v", statuses, children, children1)
   205  			t.Fatal(e)
   206  		}
   207  	}
   208  
   209  	// ===================================================================================================
   210  	// test SupervisorStrategyRestartTemporary
   211  
   212  	// testing temporary
   213  	// A temporary child process is never restarted (even when the supervisor's
   214  	// restart strategy is rest_for_one or one_for_all and a sibling's death
   215  	// causes the temporary process to be terminated).
   216  	testCases = []ChildrenTestCase{
   217  		{
   218  			reason:   "normal",
   219  			statuses: []string{"empty", "old", "old"},
   220  			events:   1, // waiting for 1 terminate
   221  		},
   222  		{
   223  			reason:   "abnormal",
   224  			statuses: []string{"old", "empty", "old"},
   225  			events:   1, // waiting for 1 terminate
   226  		},
   227  		{
   228  			reason:   "shutdown",
   229  			statuses: []string{"old", "old", "empty"},
   230  			events:   1, // waiting for 1 terminate
   231  		},
   232  	}
   233  
   234  	for i := range testCases {
   235  		fmt.Printf("Starting supervisor 'testSupervisorTemporary' (%s)... ", gen.SupervisorStrategyRestartTemporary)
   236  		sv = &testSupervisorRestForOne{
   237  			ch: make(chan interface{}, 10),
   238  		}
   239  		processSV, _ = node1.Spawn("testSupervisorTemporary", gen.ProcessOptions{}, sv, gen.SupervisorStrategyRestartTemporary, sv.ch)
   240  		children = make([]etf.Pid, 3)
   241  
   242  		children, err = waitNeventsSupervisorChildren(sv.ch, 3, children)
   243  		if err != nil {
   244  			t.Fatal(err)
   245  		} else {
   246  			fmt.Println("OK")
   247  		}
   248  
   249  		fmt.Printf("... stopping child %d with '%s' reason and without restarting  ... ", i+1, testCases[i].reason)
   250  		processSV.Send(children[i], testCases[i].reason) // stopping child
   251  
   252  		if children1, err := waitNeventsSupervisorChildren(sv.ch, testCases[i].events, children); err != nil {
   253  			t.Fatal(err)
   254  		} else {
   255  			if checkExpectedChildrenStatus(children[:], children1[:], testCases[i].statuses) {
   256  				fmt.Println("OK")
   257  				children = children1
   258  			} else {
   259  				e := fmt.Errorf("got something else except we expected (%v). old: %v new: %v", testCases[i].statuses, children, children1)
   260  				t.Fatal(e)
   261  			}
   262  		}
   263  
   264  		fmt.Printf("Stopping supervisor 'testSupervisorTemporary' (%s)... ", gen.SupervisorStrategyRestartTemporary)
   265  		processSV.Exit("x")
   266  		if children1, err := waitNeventsSupervisorChildren(sv.ch, 3-testCases[i].events, children); err != nil {
   267  			t.Fatal(err)
   268  		} else {
   269  			statuses := []string{"empty", "empty", "empty"}
   270  			if checkExpectedChildrenStatus(children[:], children1[:], statuses) {
   271  				fmt.Println("OK")
   272  				children = children1
   273  			} else {
   274  				e := fmt.Errorf("got something else except we expected (%v). old: %v new: %v", statuses, children, children1)
   275  				t.Fatal(e)
   276  			}
   277  		}
   278  	}
   279  
   280  }
   281  
   282  func (ts *testSupervisorRestForOne) Init(args ...etf.Term) (gen.SupervisorSpec, error) {
   283  	restart := args[0].(string)
   284  	ch := args[1].(chan interface{})
   285  	return gen.SupervisorSpec{
   286  		Children: []gen.SupervisorChildSpec{
   287  			{
   288  				Name:  "testGS1",
   289  				Child: &testSupervisorGenServer{},
   290  				Args:  []etf.Term{ch, 0},
   291  			},
   292  			{
   293  				Name:  "testGS2",
   294  				Child: &testSupervisorGenServer{},
   295  				Args:  []etf.Term{ch, 1},
   296  			},
   297  			{
   298  				Name:  "testGS3",
   299  				Child: &testSupervisorGenServer{},
   300  				Args:  []etf.Term{ch, 2},
   301  			},
   302  		},
   303  		Strategy: gen.SupervisorStrategy{
   304  			Type:      gen.SupervisorStrategyRestForOne,
   305  			Intensity: 10,
   306  			Period:    5,
   307  			Restart:   restart,
   308  		},
   309  	}, nil
   310  }