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

     1  package utils_test
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/git-amp/amp-sdk-go/stdlib/utils"
     9  )
    10  
    11  func TestWaitGroupChan(t *testing.T) {
    12  	t.Parallel()
    13  
    14  	t.Run("with no context cancellation, releases only after sufficiently many calls to Done()", func(t *testing.T) {
    15  		t.Parallel()
    16  
    17  		wg := utils.NewWaitGroupChan(context.Background())
    18  		defer wg.Close()
    19  
    20  		wg.Add(5)
    21  
    22  		select {
    23  		case <-wg.Wait():
    24  			t.Fatal("ended too soon")
    25  		case <-time.After(1 * time.Second):
    26  		}
    27  
    28  		wg.Done()
    29  
    30  		select {
    31  		case <-wg.Wait():
    32  			t.Fatal("ended too soon")
    33  		case <-time.After(1 * time.Second):
    34  		}
    35  
    36  		wg.Done()
    37  
    38  		select {
    39  		case <-wg.Wait():
    40  			t.Fatal("ended too soon")
    41  		case <-time.After(1 * time.Second):
    42  		}
    43  
    44  		wg.Done()
    45  
    46  		select {
    47  		case <-wg.Wait():
    48  			t.Fatal("ended too soon")
    49  		case <-time.After(1 * time.Second):
    50  		}
    51  
    52  		wg.Done()
    53  
    54  		select {
    55  		case <-wg.Wait():
    56  			t.Fatal("ended too soon")
    57  		case <-time.After(1 * time.Second):
    58  		}
    59  
    60  		wg.Done()
    61  
    62  		select {
    63  		case <-wg.Wait():
    64  		case <-time.After(1 * time.Second):
    65  			t.Fatal("did not end")
    66  		}
    67  	})
    68  
    69  	t.Run("releases after the context expires, even if Done() has not been called enough", func(t *testing.T) {
    70  		t.Parallel()
    71  
    72  		ctx, cancel := context.WithCancel(context.Background())
    73  		defer cancel()
    74  
    75  		wg := utils.NewWaitGroupChan(ctx)
    76  		defer wg.Close()
    77  
    78  		wg.Add(5)
    79  
    80  		select {
    81  		case <-wg.Wait():
    82  			t.Fatal("ended too soon")
    83  		case <-time.After(1 * time.Second):
    84  		}
    85  
    86  		wg.Done()
    87  
    88  		select {
    89  		case <-wg.Wait():
    90  			t.Fatal("ended too soon")
    91  		case <-time.After(1 * time.Second):
    92  		}
    93  
    94  		cancel()
    95  
    96  		select {
    97  		case <-wg.Wait():
    98  		case <-time.After(1 * time.Second):
    99  			t.Fatal("did not end")
   100  		}
   101  	})
   102  }
   103  
   104  func TestCombinedContext(t *testing.T) {
   105  	t.Parallel()
   106  
   107  	t.Run("cancels when an inner context is canceled", func(t *testing.T) {
   108  		t.Parallel()
   109  
   110  		innerCtx, innerCancel := context.WithCancel(context.Background())
   111  		defer innerCancel()
   112  
   113  		chStop := make(chan struct{})
   114  
   115  		ctx, cancel := utils.CombinedContext(innerCtx, chStop, 1*time.Hour)
   116  		defer cancel()
   117  
   118  		innerCancel()
   119  
   120  		select {
   121  		case <-ctx.Done():
   122  		case <-time.After(5 * time.Second):
   123  			t.Fatal("context didn't cancel")
   124  		}
   125  	})
   126  
   127  	t.Run("cancels when a channel is closed", func(t *testing.T) {
   128  		t.Parallel()
   129  
   130  		innerCtx, innerCancel := context.WithCancel(context.Background())
   131  		defer innerCancel()
   132  
   133  		chStop := make(chan struct{})
   134  
   135  		ctx, cancel := utils.CombinedContext(innerCtx, chStop, 1*time.Hour)
   136  		defer cancel()
   137  
   138  		close(chStop)
   139  
   140  		select {
   141  		case <-ctx.Done():
   142  		case <-time.After(5 * time.Second):
   143  			t.Fatal("context didn't cancel")
   144  		}
   145  	})
   146  
   147  	t.Run("cancels when a duration elapses", func(t *testing.T) {
   148  		t.Parallel()
   149  
   150  		innerCtx, innerCancel := context.WithCancel(context.Background())
   151  		defer innerCancel()
   152  
   153  		chStop := make(chan struct{})
   154  
   155  		ctx, cancel := utils.CombinedContext(innerCtx, chStop, 1*time.Second)
   156  		defer cancel()
   157  
   158  		select {
   159  		case <-ctx.Done():
   160  		case <-time.After(5 * time.Second):
   161  			t.Fatal("context didn't cancel")
   162  		}
   163  	})
   164  
   165  	t.Run("doesn't cancel if none of its children cancel", func(t *testing.T) {
   166  		t.Parallel()
   167  
   168  		innerCtx, innerCancel := context.WithCancel(context.Background())
   169  		defer innerCancel()
   170  
   171  		chStop := make(chan struct{})
   172  
   173  		ctx, cancel := utils.CombinedContext(innerCtx, chStop, 1*time.Hour)
   174  		defer cancel()
   175  
   176  		select {
   177  		case <-ctx.Done():
   178  			t.Fatal("context canceled")
   179  		case <-time.After(5 * time.Second):
   180  		}
   181  	})
   182  }
   183  
   184  func TestChanContext(t *testing.T) {
   185  	ctx := utils.ChanContext(make(chan struct{}))
   186  
   187  	go func() {
   188  		time.Sleep(1 * time.Second)
   189  		close(ctx)
   190  	}()
   191  
   192  	select {
   193  	case <-time.After(5 * time.Second):
   194  		t.Fatal("fail")
   195  	case <-ctx.Done():
   196  	}
   197  
   198  	ctx = utils.ChanContext(make(chan struct{}))
   199  	ctx2, _ := context.WithTimeout(ctx, 1*time.Second)
   200  
   201  	select {
   202  	case <-time.After(5 * time.Second):
   203  		t.Fatal("fail")
   204  	case <-ctx2.Done():
   205  	}
   206  
   207  	ctx = utils.ChanContext(make(chan struct{}))
   208  	ctx2, cancel := context.WithTimeout(ctx, 3*time.Second)
   209  
   210  	go func() {
   211  		time.Sleep(1 * time.Second)
   212  		cancel()
   213  	}()
   214  
   215  	select {
   216  	case <-time.After(5 * time.Second):
   217  		t.Fatal("fail")
   218  	case <-ctx2.Done():
   219  	}
   220  }