github.com/timandy/routine@v1.1.4-0.20240507073150-e4a3e1fe2ba5/api_routine_test.go (about) 1 package routine 2 3 import ( 4 "io" 5 "os" 6 "path" 7 "strconv" 8 "strings" 9 "sync" 10 "testing" 11 "time" 12 13 "github.com/stretchr/testify/assert" 14 ) 15 16 func TestRunnable(t *testing.T) { 17 count := 0 18 var runnable Runnable = func() { 19 count++ 20 } 21 runnable() 22 assert.Equal(t, 1, count) 23 // 24 var fun func() = runnable 25 fun() 26 assert.Equal(t, 2, count) 27 } 28 29 func TestCallable(t *testing.T) { 30 var callable Callable[string] = func() string { 31 return "Hello" 32 } 33 assert.Equal(t, "Hello", callable()) 34 // 35 var fun func() string = callable 36 assert.Equal(t, "Hello", fun()) 37 } 38 39 func TestCancelRunnable(t *testing.T) { 40 count := 0 41 var cancelRunnable CancelRunnable = func(token CancelToken) { 42 count++ 43 } 44 cancelRunnable(nil) 45 assert.Equal(t, 1, count) 46 // 47 var fun func(CancelToken) = cancelRunnable 48 fun(nil) 49 assert.Equal(t, 2, count) 50 } 51 52 func TestCancelCallable(t *testing.T) { 53 var cancelCallable CancelCallable[string] = func(token CancelToken) string { 54 return "Hello" 55 } 56 assert.Equal(t, "Hello", cancelCallable(nil)) 57 // 58 var fun func(CancelToken) string = cancelCallable 59 assert.Equal(t, "Hello", fun(nil)) 60 } 61 62 func TestWrapTask_NoContext(t *testing.T) { 63 run := false 64 wrappedRun := false 65 wg := &sync.WaitGroup{} 66 wg.Add(1) 67 tls := NewThreadLocal[string]() 68 tlsInherit := NewInheritableThreadLocal[string]() 69 tls.Set("hello") 70 tlsInherit.Set("inherit hello") 71 assert.Equal(t, "hello", tls.Get()) 72 assert.Equal(t, "inherit hello", tlsInherit.Get()) 73 task := WrapTask(func() { 74 assert.Equal(t, "", tls.Get()) 75 assert.Equal(t, "inherit hello", tlsInherit.Get()) 76 tls.Set("世界") 77 tlsInherit.Set("inherit 世界") 78 assert.Equal(t, "世界", tls.Get()) 79 assert.Equal(t, "inherit 世界", tlsInherit.Get()) 80 wrappedRun = true 81 }) 82 tls.Set("world") 83 tlsInherit.Set("inherit world") 84 assert.Equal(t, "world", tls.Get()) 85 assert.Equal(t, "inherit world", tlsInherit.Get()) 86 go func() { 87 task.Run() 88 assert.Equal(t, "", tls.Get()) 89 assert.Equal(t, "", tlsInherit.Get()) 90 run = true 91 wg.Done() 92 }() 93 assert.Equal(t, "world", tls.Get()) 94 assert.Equal(t, "inherit world", tlsInherit.Get()) 95 wg.Wait() 96 assert.True(t, wrappedRun) 97 assert.True(t, run) 98 } 99 100 func TestWrapTask_HasContext(t *testing.T) { 101 run := false 102 wrappedRun := false 103 wg := &sync.WaitGroup{} 104 wg.Add(1) 105 tls := NewThreadLocal[string]() 106 tlsInherit := NewInheritableThreadLocal[string]() 107 tls.Set("hello") 108 tlsInherit.Set("inherit hello") 109 assert.Equal(t, "hello", tls.Get()) 110 assert.Equal(t, "inherit hello", tlsInherit.Get()) 111 task := WrapTask(func() { 112 assert.Equal(t, "", tls.Get()) 113 assert.Equal(t, "inherit hello", tlsInherit.Get()) 114 tls.Set("世界") 115 tlsInherit.Set("inherit 世界") 116 assert.Equal(t, "世界", tls.Get()) 117 assert.Equal(t, "inherit 世界", tlsInherit.Get()) 118 wrappedRun = true 119 }) 120 tls.Set("world") 121 tlsInherit.Set("inherit world") 122 assert.Equal(t, "world", tls.Get()) 123 assert.Equal(t, "inherit world", tlsInherit.Get()) 124 go func() { 125 tls.Set("你好") 126 tlsInherit.Set("inherit 你好") 127 task.Run() 128 assert.Equal(t, "你好", tls.Get()) 129 assert.Equal(t, "inherit 你好", tlsInherit.Get()) 130 run = true 131 wg.Done() 132 }() 133 assert.Equal(t, "world", tls.Get()) 134 assert.Equal(t, "inherit world", tlsInherit.Get()) 135 wg.Wait() 136 assert.True(t, wrappedRun) 137 assert.True(t, run) 138 } 139 140 func TestWrapTask_Complete_ThenFail(t *testing.T) { 141 newStdout, oldStdout := captureStdout() 142 defer restoreStdout(newStdout, oldStdout) 143 // 144 run := false 145 wg := &sync.WaitGroup{} 146 wg.Add(1) 147 wg2 := &sync.WaitGroup{} 148 wg2.Add(1) 149 wg3 := &sync.WaitGroup{} 150 wg3.Add(1) 151 task := WrapTask(func() { 152 wg.Done() //1 153 wg2.Wait() //4 154 run = true 155 wg3.Done() //5 156 panic(1) 157 }) 158 go task.Run() 159 wg.Wait() //2 160 task.Complete(nil) 161 assert.Nil(t, task.Get()) 162 wg2.Done() //3 163 wg3.Wait() //6 164 assert.True(t, task.IsDone()) 165 assert.False(t, task.IsFailed()) 166 assert.False(t, task.IsCanceled()) 167 assert.True(t, run) 168 // 169 time.Sleep(10 * time.Millisecond) 170 output := readAll(newStdout) 171 assert.Equal(t, "", output) 172 } 173 174 func TestWrapWaitTask_NoContext(t *testing.T) { 175 run := false 176 wrappedRun := false 177 wg := &sync.WaitGroup{} 178 wg.Add(1) 179 tls := NewThreadLocal[string]() 180 tlsInherit := NewInheritableThreadLocal[string]() 181 tls.Set("hello") 182 tlsInherit.Set("inherit hello") 183 assert.Equal(t, "hello", tls.Get()) 184 assert.Equal(t, "inherit hello", tlsInherit.Get()) 185 task := WrapWaitTask(func(token CancelToken) { 186 assert.Equal(t, "", tls.Get()) 187 assert.Equal(t, "inherit hello", tlsInherit.Get()) 188 tls.Set("世界") 189 tlsInherit.Set("inherit 世界") 190 assert.Equal(t, "世界", tls.Get()) 191 assert.Equal(t, "inherit 世界", tlsInherit.Get()) 192 wrappedRun = true 193 }) 194 tls.Set("world") 195 tlsInherit.Set("inherit world") 196 assert.Equal(t, "world", tls.Get()) 197 assert.Equal(t, "inherit world", tlsInherit.Get()) 198 go func() { 199 task.Run() 200 assert.Equal(t, "", tls.Get()) 201 assert.Equal(t, "", tlsInherit.Get()) 202 run = true 203 wg.Done() 204 }() 205 assert.Equal(t, "world", tls.Get()) 206 assert.Equal(t, "inherit world", tlsInherit.Get()) 207 assert.Nil(t, task.Get()) 208 assert.True(t, wrappedRun) 209 wg.Wait() 210 assert.True(t, wrappedRun) 211 assert.True(t, run) 212 } 213 214 func TestWrapWaitTask_NoContext_Cancel(t *testing.T) { 215 run := false 216 wrappedRun := false 217 wg := &sync.WaitGroup{} 218 wg.Add(1) 219 tls := NewThreadLocal[string]() 220 tlsInherit := NewInheritableThreadLocal[string]() 221 tls.Set("hello") 222 tlsInherit.Set("inherit hello") 223 assert.Equal(t, "hello", tls.Get()) 224 assert.Equal(t, "inherit hello", tlsInherit.Get()) 225 task := WrapWaitTask(func(token CancelToken) { 226 for i := 0; i < 1000; i++ { 227 if token.IsCanceled() { 228 return 229 } 230 time.Sleep(1 * time.Millisecond) 231 } 232 wrappedRun = true 233 }) 234 tls.Set("world") 235 tlsInherit.Set("inherit world") 236 assert.Equal(t, "world", tls.Get()) 237 assert.Equal(t, "inherit world", tlsInherit.Get()) 238 go func() { 239 task.Run() 240 assert.Equal(t, "", tls.Get()) 241 assert.Equal(t, "", tlsInherit.Get()) 242 run = true 243 wg.Done() 244 }() 245 assert.Equal(t, "world", tls.Get()) 246 assert.Equal(t, "inherit world", tlsInherit.Get()) 247 task.Cancel() 248 assert.True(t, task.IsCanceled()) 249 assert.Panics(t, func() { 250 task.Get() 251 }) 252 assert.False(t, wrappedRun) 253 wg.Wait() 254 assert.False(t, wrappedRun) 255 assert.True(t, run) 256 } 257 258 func TestWrapWaitTask_HasContext(t *testing.T) { 259 run := false 260 wrappedRun := false 261 wg := &sync.WaitGroup{} 262 wg.Add(1) 263 tls := NewThreadLocal[string]() 264 tlsInherit := NewInheritableThreadLocal[string]() 265 tls.Set("hello") 266 tlsInherit.Set("inherit hello") 267 assert.Equal(t, "hello", tls.Get()) 268 assert.Equal(t, "inherit hello", tlsInherit.Get()) 269 task := WrapWaitTask(func(token CancelToken) { 270 assert.Equal(t, "", tls.Get()) 271 assert.Equal(t, "inherit hello", tlsInherit.Get()) 272 tls.Set("世界") 273 tlsInherit.Set("inherit 世界") 274 assert.Equal(t, "世界", tls.Get()) 275 assert.Equal(t, "inherit 世界", tlsInherit.Get()) 276 wrappedRun = true 277 }) 278 tls.Set("world") 279 tlsInherit.Set("inherit world") 280 assert.Equal(t, "world", tls.Get()) 281 assert.Equal(t, "inherit world", tlsInherit.Get()) 282 go func() { 283 tls.Set("你好") 284 tlsInherit.Set("inherit 你好") 285 task.Run() 286 assert.Equal(t, "你好", tls.Get()) 287 assert.Equal(t, "inherit 你好", tlsInherit.Get()) 288 run = true 289 wg.Done() 290 }() 291 assert.Equal(t, "world", tls.Get()) 292 assert.Equal(t, "inherit world", tlsInherit.Get()) 293 assert.Nil(t, task.Get()) 294 assert.True(t, wrappedRun) 295 wg.Wait() 296 assert.True(t, wrappedRun) 297 assert.True(t, run) 298 } 299 300 func TestWrapWaitTask_HasContext_Cancel(t *testing.T) { 301 run := false 302 wrappedRun := false 303 wg := &sync.WaitGroup{} 304 wg.Add(1) 305 tls := NewThreadLocal[string]() 306 tlsInherit := NewInheritableThreadLocal[string]() 307 tls.Set("hello") 308 tlsInherit.Set("inherit hello") 309 assert.Equal(t, "hello", tls.Get()) 310 assert.Equal(t, "inherit hello", tlsInherit.Get()) 311 task := WrapWaitTask(func(token CancelToken) { 312 for i := 0; i < 1000; i++ { 313 if token.IsCanceled() { 314 return 315 } 316 time.Sleep(1 * time.Millisecond) 317 } 318 wrappedRun = true 319 }) 320 tls.Set("world") 321 tlsInherit.Set("inherit world") 322 assert.Equal(t, "world", tls.Get()) 323 assert.Equal(t, "inherit world", tlsInherit.Get()) 324 go func() { 325 tls.Set("你好") 326 tlsInherit.Set("inherit 你好") 327 task.Run() 328 assert.Equal(t, "你好", tls.Get()) 329 assert.Equal(t, "inherit 你好", tlsInherit.Get()) 330 run = true 331 wg.Done() 332 }() 333 assert.Equal(t, "world", tls.Get()) 334 assert.Equal(t, "inherit world", tlsInherit.Get()) 335 task.Cancel() 336 assert.True(t, task.IsCanceled()) 337 assert.Panics(t, func() { 338 task.Get() 339 }) 340 assert.False(t, wrappedRun) 341 wg.Wait() 342 assert.False(t, wrappedRun) 343 assert.True(t, run) 344 } 345 346 func TestWrapWaitTask_Complete_ThenFail(t *testing.T) { 347 newStdout, oldStdout := captureStdout() 348 defer restoreStdout(newStdout, oldStdout) 349 // 350 run := false 351 wg := &sync.WaitGroup{} 352 wg.Add(1) 353 wg2 := &sync.WaitGroup{} 354 wg2.Add(1) 355 wg3 := &sync.WaitGroup{} 356 wg3.Add(1) 357 task := WrapWaitTask(func(token CancelToken) { 358 wg.Done() //1 359 wg2.Wait() //4 360 run = true 361 wg3.Done() //5 362 panic(1) 363 }) 364 go task.Run() 365 wg.Wait() //2 366 task.Complete(nil) 367 assert.Nil(t, task.Get()) 368 wg2.Done() //3 369 wg3.Wait() //6 370 assert.True(t, task.IsDone()) 371 assert.False(t, task.IsFailed()) 372 assert.False(t, task.IsCanceled()) 373 assert.True(t, run) 374 // 375 time.Sleep(10 * time.Millisecond) 376 output := readAll(newStdout) 377 assert.Equal(t, "", output) 378 } 379 380 func TestWrapWaitResultTask_NoContext(t *testing.T) { 381 run := false 382 wrappedRun := false 383 wg := &sync.WaitGroup{} 384 wg.Add(1) 385 tls := NewThreadLocal[string]() 386 tlsInherit := NewInheritableThreadLocal[string]() 387 tls.Set("hello") 388 tlsInherit.Set("inherit hello") 389 assert.Equal(t, "hello", tls.Get()) 390 assert.Equal(t, "inherit hello", tlsInherit.Get()) 391 task := WrapWaitResultTask(func(token CancelToken) any { 392 assert.Equal(t, "", tls.Get()) 393 assert.Equal(t, "inherit hello", tlsInherit.Get()) 394 tls.Set("世界") 395 tlsInherit.Set("inherit 世界") 396 assert.Equal(t, "世界", tls.Get()) 397 assert.Equal(t, "inherit 世界", tlsInherit.Get()) 398 wrappedRun = true 399 return 1 400 }) 401 tls.Set("world") 402 tlsInherit.Set("inherit world") 403 assert.Equal(t, "world", tls.Get()) 404 assert.Equal(t, "inherit world", tlsInherit.Get()) 405 go func() { 406 task.Run() 407 assert.Equal(t, "", tls.Get()) 408 assert.Equal(t, "", tlsInherit.Get()) 409 run = true 410 wg.Done() 411 }() 412 assert.Equal(t, "world", tls.Get()) 413 assert.Equal(t, "inherit world", tlsInherit.Get()) 414 assert.Equal(t, 1, task.Get()) 415 assert.True(t, wrappedRun) 416 wg.Wait() 417 assert.True(t, wrappedRun) 418 assert.True(t, run) 419 } 420 421 func TestWrapWaitResultTask_NoContext_Cancel(t *testing.T) { 422 run := false 423 wrappedRun := false 424 wg := &sync.WaitGroup{} 425 wg.Add(1) 426 tls := NewThreadLocal[string]() 427 tlsInherit := NewInheritableThreadLocal[string]() 428 tls.Set("hello") 429 tlsInherit.Set("inherit hello") 430 assert.Equal(t, "hello", tls.Get()) 431 assert.Equal(t, "inherit hello", tlsInherit.Get()) 432 task := WrapWaitResultTask(func(token CancelToken) any { 433 for i := 0; i < 1000; i++ { 434 if token.IsCanceled() { 435 return 0 436 } 437 time.Sleep(1 * time.Millisecond) 438 } 439 wrappedRun = true 440 return 1 441 }) 442 tls.Set("world") 443 tlsInherit.Set("inherit world") 444 assert.Equal(t, "world", tls.Get()) 445 assert.Equal(t, "inherit world", tlsInherit.Get()) 446 go func() { 447 task.Run() 448 assert.Equal(t, "", tls.Get()) 449 assert.Equal(t, "", tlsInherit.Get()) 450 run = true 451 wg.Done() 452 }() 453 assert.Equal(t, "world", tls.Get()) 454 assert.Equal(t, "inherit world", tlsInherit.Get()) 455 task.Cancel() 456 assert.True(t, task.IsCanceled()) 457 assert.Panics(t, func() { 458 task.Get() 459 }) 460 assert.False(t, wrappedRun) 461 wg.Wait() 462 assert.False(t, wrappedRun) 463 assert.True(t, run) 464 } 465 466 func TestWrapWaitResultTask_HasContext(t *testing.T) { 467 run := false 468 wrappedRun := false 469 wg := &sync.WaitGroup{} 470 wg.Add(1) 471 tls := NewThreadLocal[string]() 472 tlsInherit := NewInheritableThreadLocal[string]() 473 tls.Set("hello") 474 tlsInherit.Set("inherit hello") 475 assert.Equal(t, "hello", tls.Get()) 476 assert.Equal(t, "inherit hello", tlsInherit.Get()) 477 task := WrapWaitResultTask(func(token CancelToken) any { 478 assert.Equal(t, "", tls.Get()) 479 assert.Equal(t, "inherit hello", tlsInherit.Get()) 480 tls.Set("世界") 481 tlsInherit.Set("inherit 世界") 482 assert.Equal(t, "世界", tls.Get()) 483 assert.Equal(t, "inherit 世界", tlsInherit.Get()) 484 wrappedRun = true 485 return 1 486 }) 487 tls.Set("world") 488 tlsInherit.Set("inherit world") 489 assert.Equal(t, "world", tls.Get()) 490 assert.Equal(t, "inherit world", tlsInherit.Get()) 491 go func() { 492 tls.Set("你好") 493 tlsInherit.Set("inherit 你好") 494 task.Run() 495 assert.Equal(t, "你好", tls.Get()) 496 assert.Equal(t, "inherit 你好", tlsInherit.Get()) 497 run = true 498 wg.Done() 499 }() 500 assert.Equal(t, "world", tls.Get()) 501 assert.Equal(t, "inherit world", tlsInherit.Get()) 502 assert.Equal(t, 1, task.Get()) 503 assert.True(t, wrappedRun) 504 wg.Wait() 505 assert.True(t, wrappedRun) 506 assert.True(t, run) 507 } 508 509 func TestWrapWaitResultTask_HasContext_Cancel(t *testing.T) { 510 run := false 511 wrappedRun := false 512 wg := &sync.WaitGroup{} 513 wg.Add(1) 514 tls := NewThreadLocal[string]() 515 tlsInherit := NewInheritableThreadLocal[string]() 516 tls.Set("hello") 517 tlsInherit.Set("inherit hello") 518 assert.Equal(t, "hello", tls.Get()) 519 assert.Equal(t, "inherit hello", tlsInherit.Get()) 520 task := WrapWaitResultTask(func(token CancelToken) any { 521 for i := 0; i < 1000; i++ { 522 if token.IsCanceled() { 523 return 0 524 } 525 time.Sleep(1 * time.Millisecond) 526 } 527 wrappedRun = true 528 return 1 529 }) 530 tls.Set("world") 531 tlsInherit.Set("inherit world") 532 assert.Equal(t, "world", tls.Get()) 533 assert.Equal(t, "inherit world", tlsInherit.Get()) 534 go func() { 535 tls.Set("你好") 536 tlsInherit.Set("inherit 你好") 537 task.Run() 538 assert.Equal(t, "你好", tls.Get()) 539 assert.Equal(t, "inherit 你好", tlsInherit.Get()) 540 run = true 541 wg.Done() 542 }() 543 assert.Equal(t, "world", tls.Get()) 544 assert.Equal(t, "inherit world", tlsInherit.Get()) 545 task.Cancel() 546 assert.True(t, task.IsCanceled()) 547 assert.Panics(t, func() { 548 task.Get() 549 }) 550 assert.False(t, wrappedRun) 551 wg.Wait() 552 assert.False(t, wrappedRun) 553 assert.True(t, run) 554 } 555 556 func TestWrapWaitResultTask_Complete_ThenFail(t *testing.T) { 557 newStdout, oldStdout := captureStdout() 558 defer restoreStdout(newStdout, oldStdout) 559 // 560 run := false 561 wg := &sync.WaitGroup{} 562 wg.Add(1) 563 wg2 := &sync.WaitGroup{} 564 wg2.Add(1) 565 wg3 := &sync.WaitGroup{} 566 wg3.Add(1) 567 task := WrapWaitResultTask(func(token CancelToken) any { 568 wg.Done() //1 569 wg2.Wait() //4 570 run = true 571 wg3.Done() //5 572 panic(1) 573 }) 574 go task.Run() 575 wg.Wait() //2 576 task.Complete(nil) 577 assert.Nil(t, task.Get()) 578 wg2.Done() //3 579 wg3.Wait() //6 580 assert.True(t, task.IsDone()) 581 assert.False(t, task.IsFailed()) 582 assert.False(t, task.IsCanceled()) 583 assert.True(t, run) 584 // 585 time.Sleep(10 * time.Millisecond) 586 output := readAll(newStdout) 587 assert.Equal(t, "", output) 588 } 589 590 func TestGo_Error(t *testing.T) { 591 newStdout, oldStdout := captureStdout() 592 defer restoreStdout(newStdout, oldStdout) 593 // 594 run := false 595 assert.NotPanics(t, func() { 596 wg := &sync.WaitGroup{} 597 wg.Add(1) 598 Go(func() { 599 run = true 600 wg.Done() 601 panic("error") 602 }) 603 wg.Wait() 604 }) 605 assert.True(t, run) 606 // 607 time.Sleep(10 * time.Millisecond) 608 output := readAll(newStdout) 609 lines := strings.Split(output, newLine) 610 assert.Equal(t, 7, len(lines)) 611 // 612 line := lines[0] 613 assert.Equal(t, "RuntimeError: error", line) 614 // 615 line = lines[1] 616 assert.True(t, strings.HasPrefix(line, " at github.com/timandy/routine.TestGo_Error.")) 617 assert.True(t, strings.HasSuffix(line, "api_routine_test.go:601")) 618 // 619 line = lines[2] 620 assert.True(t, strings.HasPrefix(line, " at github.com/timandy/routine.inheritedTask.run()")) 621 assert.True(t, strings.HasSuffix(line, "routine.go:31")) 622 // 623 line = lines[3] 624 assert.True(t, strings.HasPrefix(line, " at github.com/timandy/routine.(*futureTask[...]).Run()")) 625 assert.True(t, strings.HasSuffix(line, "future_task.go:108")) 626 // 627 line = lines[4] 628 assert.Equal(t, " --- End of error stack trace ---", line) 629 // 630 line = lines[5] 631 assert.True(t, strings.HasPrefix(line, " created by github.com/timandy/routine.Go()")) 632 assert.True(t, strings.HasSuffix(line, "api_routine.go:49")) 633 // 634 line = lines[6] 635 assert.Equal(t, "", line) 636 } 637 638 func TestGo_Nil(t *testing.T) { 639 assert.Nil(t, createInheritedMap()) 640 // 641 run := false 642 wg := &sync.WaitGroup{} 643 wg.Add(1) 644 Go(func() { 645 assert.Nil(t, createInheritedMap()) 646 run = true 647 wg.Done() 648 }) 649 wg.Wait() 650 assert.True(t, run) 651 } 652 653 func TestGo_Value(t *testing.T) { 654 tls := NewThreadLocal[string]() 655 tls.Set("Hello") 656 assert.Equal(t, "Hello", tls.Get()) 657 // 658 inheritableTls := NewInheritableThreadLocal[string]() 659 inheritableTls.Set("World") 660 assert.Equal(t, "World", inheritableTls.Get()) 661 // 662 assert.NotNil(t, createInheritedMap()) 663 // 664 run := false 665 wg := &sync.WaitGroup{} 666 wg.Add(1) 667 Go(func() { 668 assert.NotNil(t, createInheritedMap()) 669 // 670 assert.Equal(t, "", tls.Get()) 671 assert.Equal(t, "World", inheritableTls.Get()) 672 // 673 tls.Set("Hello2") 674 assert.Equal(t, "Hello2", tls.Get()) 675 // 676 inheritableTls.Remove() 677 assert.Equal(t, "", inheritableTls.Get()) 678 // 679 run = true 680 wg.Done() 681 }) 682 wg.Wait() 683 assert.True(t, run) 684 // 685 assert.Equal(t, "Hello", tls.Get()) 686 assert.Equal(t, "World", inheritableTls.Get()) 687 } 688 689 func TestGo_Cross(t *testing.T) { 690 tls := NewThreadLocal[string]() 691 tls.Set("Hello") 692 assert.Equal(t, "Hello", tls.Get()) 693 // 694 wg := &sync.WaitGroup{} 695 wg.Add(1) 696 Go(func() { 697 assert.Equal(t, "", tls.Get()) 698 wg.Done() 699 }) 700 wg.Wait() 701 } 702 703 func TestGoWait_Error(t *testing.T) { 704 run := false 705 task := GoWait(func(token CancelToken) { 706 run = true 707 panic("error") 708 }) 709 assert.Panics(t, func() { 710 task.Get() 711 }) 712 assert.True(t, run) 713 // 714 defer func() { 715 cause := recover() 716 assert.NotNil(t, cause) 717 assert.Implements(t, (*RuntimeError)(nil), cause) 718 err := cause.(RuntimeError) 719 lines := strings.Split(err.Error(), newLine) 720 assert.Equal(t, 6, len(lines)) 721 // 722 line := lines[0] 723 assert.Equal(t, "RuntimeError: error", line) 724 // 725 line = lines[1] 726 assert.True(t, strings.HasPrefix(line, " at github.com/timandy/routine.TestGoWait_Error.")) 727 assert.True(t, strings.HasSuffix(line, "api_routine_test.go:707")) 728 // 729 line = lines[2] 730 assert.True(t, strings.HasPrefix(line, " at github.com/timandy/routine.inheritedWaitTask.run()")) 731 assert.True(t, strings.HasSuffix(line, "routine.go:70")) 732 // 733 line = lines[3] 734 assert.True(t, strings.HasPrefix(line, " at github.com/timandy/routine.(*futureTask[...]).Run()")) 735 assert.True(t, strings.HasSuffix(line, "future_task.go:108")) 736 // 737 line = lines[4] 738 assert.Equal(t, " --- End of error stack trace ---", line) 739 // 740 line = lines[5] 741 assert.True(t, strings.HasPrefix(line, " created by github.com/timandy/routine.GoWait()")) 742 assert.True(t, strings.HasSuffix(line, "api_routine.go:57")) 743 }() 744 task.Get() 745 } 746 747 func TestGoWait_Nil(t *testing.T) { 748 assert.Nil(t, createInheritedMap()) 749 // 750 run := false 751 task := GoWait(func(token CancelToken) { 752 assert.Nil(t, createInheritedMap()) 753 run = true 754 }) 755 assert.Nil(t, task.Get()) 756 assert.True(t, run) 757 } 758 759 func TestGoWait_Value(t *testing.T) { 760 tls := NewThreadLocal[string]() 761 tls.Set("Hello") 762 assert.Equal(t, "Hello", tls.Get()) 763 // 764 inheritableTls := NewInheritableThreadLocal[string]() 765 inheritableTls.Set("World") 766 assert.Equal(t, "World", inheritableTls.Get()) 767 // 768 assert.NotNil(t, createInheritedMap()) 769 // 770 run := false 771 task := GoWait(func(token CancelToken) { 772 assert.NotNil(t, createInheritedMap()) 773 // 774 assert.Equal(t, "", tls.Get()) 775 assert.Equal(t, "World", inheritableTls.Get()) 776 // 777 tls.Set("Hello2") 778 assert.Equal(t, "Hello2", tls.Get()) 779 // 780 inheritableTls.Remove() 781 assert.Equal(t, "", inheritableTls.Get()) 782 // 783 run = true 784 }) 785 assert.Nil(t, task.Get()) 786 assert.True(t, run) 787 // 788 assert.Equal(t, "Hello", tls.Get()) 789 assert.Equal(t, "World", inheritableTls.Get()) 790 } 791 792 func TestGoWait_Cross(t *testing.T) { 793 tls := NewThreadLocal[string]() 794 tls.Set("Hello") 795 assert.Equal(t, "Hello", tls.Get()) 796 // 797 GoWait(func(token CancelToken) { 798 assert.Equal(t, "", tls.Get()) 799 }).Get() 800 } 801 802 func TestGoWaitResult_Error(t *testing.T) { 803 run := false 804 task := GoWaitResult(func(token CancelToken) int { 805 run = true 806 if run { 807 panic("error") 808 } 809 return 1 810 }) 811 assert.Panics(t, func() { 812 task.Get() 813 }) 814 assert.True(t, run) 815 // 816 defer func() { 817 cause := recover() 818 assert.NotNil(t, cause) 819 assert.Implements(t, (*RuntimeError)(nil), cause) 820 err := cause.(RuntimeError) 821 lines := strings.Split(err.Error(), newLine) 822 assert.True(t, len(lines) == 6 || len(lines) == 7) 823 // 824 line := lines[0] 825 assert.Equal(t, "RuntimeError: error", line) 826 // 827 line = lines[1] 828 assert.True(t, strings.HasPrefix(line, " at github.com/timandy/routine.TestGoWaitResult_Error.")) 829 assert.True(t, strings.HasSuffix(line, "api_routine_test.go:807")) 830 // 831 line = lines[2] 832 assert.True(t, strings.HasPrefix(line, " at github.com/timandy/routine.inheritedWaitResultTask[...].run()")) 833 assert.True(t, strings.HasSuffix(line, "routine.go:109")) 834 // 835 lineOffset := 0 836 if len(lines) == 7 { 837 line = lines[3+lineOffset] 838 lineOffset = 1 839 assert.True(t, strings.HasPrefix(line, " at github.com/timandy/routine.WrapWaitResultTask[...].func1()")) 840 assert.True(t, strings.HasSuffix(line, "api_routine.go:41")) 841 } 842 // 843 line = lines[3+lineOffset] 844 assert.True(t, strings.HasPrefix(line, " at github.com/timandy/routine.(*futureTask[...]).Run()")) 845 assert.True(t, strings.HasSuffix(line, "future_task.go:108")) 846 // 847 line = lines[4+lineOffset] 848 assert.Equal(t, " --- End of error stack trace ---", line) 849 // 850 line = lines[5+lineOffset] 851 assert.True(t, strings.HasPrefix(line, " created by github.com/timandy/routine.GoWaitResult[...]()")) 852 assert.True(t, strings.HasSuffix(line, "api_routine.go:66")) 853 }() 854 task.Get() 855 } 856 857 func TestGoWaitResult_Nil(t *testing.T) { 858 assert.Nil(t, createInheritedMap()) 859 // 860 run := false 861 task := GoWaitResult(func(token CancelToken) bool { 862 assert.Nil(t, createInheritedMap()) 863 run = true 864 return true 865 }) 866 assert.True(t, task.Get()) 867 assert.True(t, run) 868 } 869 870 func TestGoWaitResult_Value(t *testing.T) { 871 tls := NewThreadLocal[string]() 872 tls.Set("Hello") 873 assert.Equal(t, "Hello", tls.Get()) 874 // 875 inheritableTls := NewInheritableThreadLocal[string]() 876 inheritableTls.Set("World") 877 assert.Equal(t, "World", inheritableTls.Get()) 878 // 879 assert.NotNil(t, createInheritedMap()) 880 // 881 run := false 882 task := GoWaitResult(func(token CancelToken) bool { 883 assert.NotNil(t, createInheritedMap()) 884 // 885 assert.Equal(t, "", tls.Get()) 886 assert.Equal(t, "World", inheritableTls.Get()) 887 // 888 tls.Set("Hello2") 889 assert.Equal(t, "Hello2", tls.Get()) 890 // 891 inheritableTls.Remove() 892 assert.Equal(t, "", inheritableTls.Get()) 893 // 894 run = true 895 return true 896 }) 897 assert.True(t, task.Get()) 898 assert.True(t, run) 899 // 900 assert.Equal(t, "Hello", tls.Get()) 901 assert.Equal(t, "World", inheritableTls.Get()) 902 } 903 904 func TestGoWaitResult_Cross(t *testing.T) { 905 tls := NewThreadLocal[string]() 906 tls.Set("Hello") 907 assert.Equal(t, "Hello", tls.Get()) 908 // 909 result := GoWaitResult(func(token CancelToken) string { 910 assert.Equal(t, "", tls.Get()) 911 return tls.Get() 912 }).Get() 913 assert.Equal(t, "", result) 914 } 915 916 func captureStdout() (newStdout, oldStdout *os.File) { 917 oldStdout = os.Stdout 918 fileName := path.Join(os.TempDir(), "go_test_"+strconv.FormatInt(time.Now().UnixNano(), 10)+".txt") 919 file, err := os.Create(fileName) 920 if err != nil { 921 panic(err) 922 } 923 os.Stdout = file 924 newStdout = file 925 return 926 } 927 928 func restoreStdout(newStdout, oldStdout *os.File) { 929 os.Stdout = oldStdout 930 if err := newStdout.Close(); err != nil { 931 panic(err) 932 } 933 if err := os.Remove(newStdout.Name()); err != nil { 934 panic(err) 935 } 936 } 937 938 func readAll(rs io.ReadSeeker) string { 939 if _, err := rs.Seek(0, io.SeekStart); err != nil { 940 panic(err) 941 } 942 b := make([]byte, 0, 512) 943 for { 944 if len(b) == cap(b) { 945 b = append(b, 0)[:len(b)] 946 } 947 n, err := rs.Read(b[len(b):cap(b)]) 948 b = b[:len(b)+n] 949 if err != nil { 950 if err == io.EOF { 951 return string(b) 952 } 953 panic(err) 954 } 955 } 956 }