github.com/yunabe/lgo@v0.0.0-20190709125917-42c42d410fdf/core/core_test.go (about)

     1  package core
     2  
     3  import (
     4  	"context"
     5  	"sync/atomic"
     6  	"testing"
     7  	"time"
     8  )
     9  
    10  func TestExecutionContextCancel(t *testing.T) {
    11  	atomic.StoreUint32(&isRunning, 0)
    12  	startExec(LgoContext{Context: context.Background()}, func() {})
    13  
    14  	if running := atomic.LoadUint32(&isRunning); running != 1 {
    15  		t.Errorf("Expected 1 but got %d", running)
    16  	}
    17  	e := getExecState()
    18  	select {
    19  	case <-e.Context.Done():
    20  		t.Error("e.Context is canceled unexpectedly")
    21  	default:
    22  	}
    23  	// Nothing happens
    24  	ExitIfCtxDone()
    25  
    26  	e.cancel()
    27  
    28  	select {
    29  	case <-e.Context.Done():
    30  	default:
    31  		t.Error("e.Context is not canceled")
    32  	}
    33  	if running := atomic.LoadUint32(&isRunning); running != 0 {
    34  		t.Errorf("Expected 0 but got %d", running)
    35  	}
    36  	defer func() {
    37  		r := recover()
    38  		if r != Bailout {
    39  			t.Errorf("ExitIfDone paniced with an expected value: %v", r)
    40  		}
    41  	}()
    42  	// panic with Bailout
    43  	ExitIfCtxDone()
    44  }
    45  
    46  func TestMainCounters(t *testing.T) {
    47  	tests := []struct {
    48  		name    string
    49  		body    func()
    50  		message string
    51  	}{
    52  		{
    53  			name: "ok",
    54  			body: func() {},
    55  		}, {
    56  			name:    "fail",
    57  			message: "main routine failed",
    58  			body:    func() { panic("fail") },
    59  		}, {
    60  			name:    "cancel",
    61  			message: "main routine canceled",
    62  			body:    func() { panic(Bailout) },
    63  		}, {
    64  			name:    "gofail",
    65  			message: "1 goroutine failed",
    66  			body: func() {
    67  				state := InitGoroutine()
    68  				go func() {
    69  					defer FinalizeGoroutine(state)
    70  					panic("fail")
    71  				}()
    72  			},
    73  		}, {
    74  			name:    "gocancel",
    75  			message: "1 goroutine canceled",
    76  			body: func() {
    77  				state := InitGoroutine()
    78  				go func() {
    79  					defer FinalizeGoroutine(state)
    80  					panic(Bailout)
    81  				}()
    82  			},
    83  		}, {
    84  			name:    "gofailmulti",
    85  			message: "2 goroutines failed",
    86  			body: func() {
    87  				for i := 0; i < 2; i++ {
    88  					state := InitGoroutine()
    89  					go func() {
    90  						defer FinalizeGoroutine(state)
    91  						panic("fail")
    92  					}()
    93  				}
    94  			},
    95  		}, {
    96  			name:    "gocancelmulti",
    97  			message: "3 goroutines canceled",
    98  			body: func() {
    99  				for i := 0; i < 3; i++ {
   100  					state := InitGoroutine()
   101  					go func() {
   102  						defer FinalizeGoroutine(state)
   103  						panic(Bailout)
   104  					}()
   105  				}
   106  			},
   107  		}, {
   108  			name:    "gomix",
   109  			message: "1 goroutine failed, 2 goroutines canceled",
   110  			body: func() {
   111  				state := InitGoroutine()
   112  				go func() {
   113  					defer FinalizeGoroutine(state)
   114  					panic("fail")
   115  				}()
   116  				for i := 0; i < 2; i++ {
   117  					state := InitGoroutine()
   118  					go func() {
   119  						defer FinalizeGoroutine(state)
   120  						panic(Bailout)
   121  					}()
   122  				}
   123  			},
   124  		},
   125  	}
   126  	for _, tc := range tests {
   127  		t.Run(tc.name, func(t *testing.T) {
   128  			atomic.StoreUint32(&isRunning, 0)
   129  			ch := make(chan struct{})
   130  			state := startExec(LgoContext{Context: context.Background()}, func() {
   131  				<-ch
   132  				tc.body()
   133  			})
   134  			initMsg := "main routine is hanging"
   135  			if msg := state.counterMessage(); msg != initMsg {
   136  				t.Fatalf("Got %q; want %q", msg, initMsg)
   137  			}
   138  			close(ch)
   139  			var msg string
   140  			if err := finalizeExec(state); err != nil {
   141  				msg = err.Error()
   142  			}
   143  			if msg != tc.message {
   144  				t.Fatalf("Got %q; want %q", msg, tc.message)
   145  			}
   146  			if err := state.Context.Err(); err != context.Canceled {
   147  				// state.Context must be canceled.
   148  				t.Errorf("Unexpected err: %v", err)
   149  			}
   150  		})
   151  	}
   152  }
   153  
   154  func TestFinalizeExecTimeout(t *testing.T) {
   155  	execWaitDuration = 10 * time.Millisecond
   156  
   157  	atomic.StoreUint32(&isRunning, 0)
   158  	state := startExec(LgoContext{Context: context.Background()}, func() {
   159  		time.Sleep(100 * time.Millisecond)
   160  	})
   161  	state.cancel()
   162  	var msg string
   163  	if err := finalizeExec(state); err != nil {
   164  		msg = err.Error()
   165  	}
   166  	want := "main routine is hanging"
   167  	if msg != want {
   168  		t.Fatalf("Got %q; want %q", msg, want)
   169  	}
   170  	if err := state.Context.Err(); err != context.Canceled {
   171  		// state.Context must be canceled.
   172  		t.Errorf("Unexpected err: %v", err)
   173  	}
   174  }