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

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