github.com/searKing/golang/go@v1.2.117/sync/until_test.go (about)

     1  // Copyright 2021 The searKing Author. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package sync_test
     6  
     7  import (
     8  	"context"
     9  	"errors"
    10  	"fmt"
    11  	"sync"
    12  	"sync/atomic"
    13  	"testing"
    14  	"time"
    15  
    16  	sync_ "github.com/searKing/golang/go/sync"
    17  )
    18  
    19  const goroutineCount = 5
    20  
    21  func TestUntil_DoTimeout(t *testing.T) {
    22  	var until sync_.Until
    23  	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond)
    24  	defer cancel()
    25  	if _, err := until.Do(ctx, func() (any, error) { return "bar", fmt.Errorf("must error") }); !errors.Is(err, context.DeadlineExceeded) {
    26  		t.Errorf("until.Do returned error %v, want DeadlineExceeded", err)
    27  	}
    28  }
    29  
    30  func TestUntil_DoBlocking(t *testing.T) {
    31  	var until sync_.Until
    32  	// All goroutines should block because picker is nil in until.
    33  	var finishedCount uint64
    34  	for i := goroutineCount; i > 0; i-- {
    35  		go func() {
    36  			if _, err := until.Do(context.Background(), nil); err == nil {
    37  				t.Errorf("until.Do returned nil error")
    38  			}
    39  			atomic.AddUint64(&finishedCount, 1)
    40  		}()
    41  	}
    42  	time.Sleep(50 * time.Millisecond)
    43  	if c := atomic.LoadUint64(&finishedCount); c != 0 {
    44  		t.Errorf("finished goroutines count: %v, want 0", c)
    45  	}
    46  	until.Close()
    47  }
    48  
    49  func TestUntil_Do(t *testing.T) {
    50  	var until sync_.Until
    51  	// All goroutines should block because picker is nil in until.
    52  	var finishedCount uint64
    53  	for i := goroutineCount; i > 0; i-- {
    54  		go func() {
    55  			if tr, err := until.Do(context.Background(), func() (any, error) {
    56  				return "bar", nil
    57  			}); err != nil || tr != "bar" {
    58  				t.Errorf("until.Do returned non-nil error: %v", err)
    59  			}
    60  			atomic.AddUint64(&finishedCount, 1)
    61  		}()
    62  	}
    63  	time.Sleep(50 * time.Millisecond)
    64  	if c := atomic.LoadUint64(&finishedCount); c != goroutineCount {
    65  		t.Errorf("finished goroutines count: %v, want 0", c)
    66  	}
    67  	until.Close()
    68  }
    69  
    70  func TestUntil_DoBlockingAndGot(t *testing.T) {
    71  	var mu sync.Mutex
    72  	var fn = func() (any, error) {
    73  		return "bar", fmt.Errorf("must error")
    74  	}
    75  
    76  	var fnHolder = func() (any, error) {
    77  		mu.Lock()
    78  		defer mu.Unlock()
    79  		return fn()
    80  	}
    81  
    82  	var until sync_.Until
    83  	// All goroutines should block because picker is nil in until.
    84  	var finishedCount uint64
    85  	for i := goroutineCount; i > 0; i-- {
    86  		go func() {
    87  			if tr, err := until.Do(context.Background(), fnHolder); err != nil || tr != "bar" {
    88  				t.Errorf("until.Do returned non-nil error: %v", err)
    89  			}
    90  			atomic.AddUint64(&finishedCount, 1)
    91  		}()
    92  	}
    93  	time.Sleep(50 * time.Millisecond)
    94  	if c := atomic.LoadUint64(&finishedCount); c != 0 {
    95  		t.Errorf("finished goroutines count: %v, want 0", c)
    96  	}
    97  	fn = func() (any, error) {
    98  		return "bar", nil
    99  	}
   100  	until.Retry()
   101  
   102  	time.Sleep(50 * time.Millisecond)
   103  	if c := atomic.LoadUint64(&finishedCount); c != goroutineCount {
   104  		t.Errorf("finished goroutines count: %v, want 0", c)
   105  	}
   106  	until.Close()
   107  }