Test singleflight behaves correctly after Do panic. See https://github.com/golang/go/issues/41133
(t *testing.T)
| 218 | // Test singleflight behaves correctly after Do panic. |
| 219 | // See https://github.com/golang/go/issues/41133 |
| 220 | func TestPanicDo(t *testing.T) { |
| 221 | var g Group[string, any] |
| 222 | fn := func() (any, error) { |
| 223 | panic("invalid memory address or nil pointer dereference") |
| 224 | } |
| 225 | |
| 226 | const n = 5 |
| 227 | waited := int32(n) |
| 228 | panicCount := int32(0) |
| 229 | done := make(chan struct{}) |
| 230 | for i := 0; i < n; i++ { |
| 231 | go func() { |
| 232 | defer func() { |
| 233 | if err := recover(); err != nil { |
| 234 | t.Logf("Got panic: %v\n%s", err, debug.Stack()) |
| 235 | atomic.AddInt32(&panicCount, 1) |
| 236 | } |
| 237 | |
| 238 | if atomic.AddInt32(&waited, -1) == 0 { |
| 239 | close(done) |
| 240 | } |
| 241 | }() |
| 242 | |
| 243 | g.Do("key", fn) |
| 244 | }() |
| 245 | } |
| 246 | |
| 247 | select { |
| 248 | case <-done: |
| 249 | if panicCount != n { |
| 250 | t.Errorf("Expect %d panic, but got %d", n, panicCount) |
| 251 | } |
| 252 | case <-time.After(time.Second): |
| 253 | t.Fatalf("Do hangs") |
| 254 | } |
| 255 | } |
| 256 | |
| 257 | func TestGoexitDo(t *testing.T) { |
| 258 | var g Group[string, any] |