(t *testing.T)
| 601 | } |
| 602 | |
| 603 | func TestConcurrentEvalProgramThreadSafety(t *testing.T) { |
| 604 | prg := mustProgram(t, `async_func(x) + 1`, |
| 605 | cel.Variable("x", cel.IntType), |
| 606 | cel.Function("async_func", |
| 607 | cel.Overload("async_func_int", []*cel.Type{cel.IntType}, cel.IntType, |
| 608 | cel.AsyncBinding(func(ctx context.Context, args ...ref.Val) ref.Val { |
| 609 | time.Sleep(5 * time.Millisecond) |
| 610 | return args[0] |
| 611 | }), |
| 612 | ), |
| 613 | ), |
| 614 | ) |
| 615 | |
| 616 | const numGoroutines = 10 |
| 617 | errCh := make(chan error, numGoroutines) |
| 618 | for i := range numGoroutines { |
| 619 | go func(val int64) { |
| 620 | res := awaitEval(t, prg, context.Background(), map[string]any{"x": val}) |
| 621 | if res.Err != nil { |
| 622 | errCh <- res.Err |
| 623 | return |
| 624 | } |
| 625 | if res.Val.Equal(types.Int(val+1)) != types.True { |
| 626 | errCh <- errors.New("unexpected eval result") |
| 627 | return |
| 628 | } |
| 629 | errCh <- nil |
| 630 | }(int64(i * 10)) |
| 631 | } |
| 632 | |
| 633 | for range numGoroutines { |
| 634 | if err := <-errCh; err != nil { |
| 635 | t.Errorf("Concurrent thread safety evaluation failed: %v", err) |
| 636 | } |
| 637 | } |
| 638 | } |
| 639 | |
| 640 | func TestConcurrentEvalPreCanceledContext(t *testing.T) { |
| 641 | prg := mustProgram(t, `async_func(42)`, |
nothing calls this directly
no test coverage detected