github.com/git-amp/amp-sdk-go@v0.7.5/stdlib/task/task_test.go (about)

     1  package task_test
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/stretchr/testify/require"
     9  
    10  	"github.com/git-amp/amp-sdk-go/stdlib/task"
    11  	"github.com/git-amp/amp-sdk-go/stdlib/testutils"
    12  )
    13  
    14  func spawnN(p task.Context, numGoroutines int, delay time.Duration) {
    15  	for i := 0; i < numGoroutines; i++ {
    16  		name := fmt.Sprintf("#%d", i+1)
    17  		p.Go(name, func(ctx task.Context) {
    18  			time.Sleep(delay)
    19  			yoyo := delay
    20  			fmt.Print(yoyo)
    21  		})
    22  	}
    23  }
    24  
    25  func TestCore(t *testing.T) {
    26  	t.Run("basic idle close", func(t *testing.T) {
    27  		p, _ := task.Start(&task.Task{
    28  			Label:     "root",
    29  			IdleClose: time.Nanosecond,
    30  		})
    31  
    32  		spawnN(p, 1, 1*time.Second)
    33  
    34  		select {
    35  		case <-time.After(2000 * time.Second):
    36  			t.Fatal("fail")
    37  		case <-p.Done():
    38  		}
    39  	})
    40  }
    41  
    42  func TestNestedIdleClose(t *testing.T) {
    43  	t.Run("nested idle close", func(t *testing.T) {
    44  		p, _ := task.Start(&task.Task{
    45  			Label:     "root",
    46  			IdleClose: time.Nanosecond,
    47  		})
    48  
    49  		child, _ := p.StartChild(&task.Task{
    50  			Label:     "child",
    51  			IdleClose: time.Nanosecond,
    52  		})
    53  		spawnN(child, 10, 1*time.Second)
    54  
    55  		select {
    56  		case <-time.After(2 * time.Second):
    57  			t.Fatal("fail")
    58  		case <-p.Done():
    59  		}
    60  	})
    61  }
    62  
    63  func TestIdleCloseWithDelay(t *testing.T) {
    64  	t.Run("idle close with delay", func(t *testing.T) {
    65  		p, _ := task.Start(&task.Task{
    66  			Label:     "root with idle close delay",
    67  			IdleClose: 2 * time.Second,
    68  		})
    69  
    70  		select {
    71  		case <-time.After(3 * time.Second):
    72  		case <-p.Done():
    73  			t.Fatal("ctx exited early")
    74  		default:
    75  		}
    76  
    77  		spawnN(p, 10, 1*time.Second)
    78  
    79  		select {
    80  		case <-time.After(4 * time.Second):
    81  			t.Fatal("fail")
    82  		case <-p.Done():
    83  		}
    84  
    85  	})
    86  }
    87  
    88  func Test6(t *testing.T) {
    89  
    90  	t.Run("close cancels children", func(t *testing.T) {
    91  		p, _ := task.Start(&task.Task{
    92  			Label: "close tester",
    93  		})
    94  
    95  		child, _ := p.StartChild(&task.Task{
    96  			Label: "child",
    97  		})
    98  
    99  		canceled1 := testutils.NewAwaiter()
   100  		canceled2 := testutils.NewAwaiter()
   101  
   102  		foo1, _ := p.Go("foo1", func(ctx task.Context) {
   103  			select {
   104  			case <-ctx.Closing():
   105  				canceled1.ItHappened()
   106  			case <-time.After(5 * time.Second):
   107  				t.Fatal("context wasn't canceled")
   108  			}
   109  		})
   110  
   111  		foo2, _ := child.Go("foo2", func(ctx task.Context) {
   112  			select {
   113  			case <-ctx.Closing():
   114  				canceled2.ItHappened()
   115  			case <-time.After(5 * time.Second):
   116  				t.Fatal("context wasn't canceled")
   117  			}
   118  
   119  		})
   120  
   121  		requireDone(t, p.Done(), false)
   122  		requireDone(t, child.Done(), false)
   123  		requireDone(t, foo1.Done(), false)
   124  		requireDone(t, foo2.Done(), false)
   125  
   126  		go p.Close()
   127  
   128  		canceled1.AwaitOrFail(t)
   129  		canceled2.AwaitOrFail(t)
   130  
   131  		require.Eventually(t, func() bool { return isDone(t, p.Done()) }, 5*time.Second, 100*time.Millisecond)
   132  		require.Eventually(t, func() bool { return isDone(t, child.Done()) }, 5*time.Second, 100*time.Millisecond)
   133  		require.Eventually(t, func() bool { return isDone(t, foo1.Done()) }, 5*time.Second, 100*time.Millisecond)
   134  		require.Eventually(t, func() bool { return isDone(t, foo2.Done()) }, 5*time.Second, 100*time.Millisecond)
   135  	})
   136  }
   137  
   138  func requireDone(t *testing.T, chDone <-chan struct{}, done bool) {
   139  	t.Helper()
   140  	require.Equal(t, done, isDone(t, chDone))
   141  }
   142  
   143  func isDone(t *testing.T, chDone <-chan struct{}) bool {
   144  	t.Helper()
   145  	select {
   146  	case <-chDone:
   147  		return true
   148  	default:
   149  		return false
   150  	}
   151  }