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 }