github.com/andy2046/gopie@v0.7.0/pkg/barrier/barrier_test.go (about)

     1  package barrier
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  	"sync/atomic"
     7  	"testing"
     8  	"time"
     9  )
    10  
    11  func TestNew(t *testing.T) {
    12  	num := 10
    13  	b := New(num)
    14  	n, nWaiting := b.N(), b.NWaiting()
    15  	isBroken := b.IsBroken()
    16  
    17  	if n != num {
    18  		t.Error("number of barrier members, expected", num, ", got", n)
    19  	}
    20  	if nWaiting != 0 {
    21  		t.Error("number of barrier members waiting, expected", 0, ", got", nWaiting)
    22  	}
    23  	if isBroken != false {
    24  		t.Error("barrier isBroken, expected", false, ", got", isBroken)
    25  	}
    26  
    27  	defer func() {
    28  		if recover() == nil {
    29  			t.Error("panic expected")
    30  		}
    31  	}()
    32  	_ = New(0)
    33  	_ = New(-1)
    34  }
    35  
    36  func TestAwaitOnce(t *testing.T) {
    37  	num := 100
    38  	b := New(num)
    39  	ctx := context.Background()
    40  
    41  	wg := sync.WaitGroup{}
    42  	for i := 0; i < num; i++ {
    43  		wg.Add(1)
    44  		go func() {
    45  			err := b.Await(ctx)
    46  			if err != nil {
    47  				panic(err)
    48  			}
    49  			wg.Done()
    50  		}()
    51  	}
    52  
    53  	wg.Wait()
    54  
    55  	n, nWaiting := b.N(), b.NWaiting()
    56  	isBroken := b.IsBroken()
    57  
    58  	if n != num {
    59  		t.Error("number of barrier members, expected", num, ", got", n)
    60  	}
    61  	if nWaiting != 0 {
    62  		t.Error("number of barrier members waiting, expected", 0, ", got", nWaiting)
    63  	}
    64  	if isBroken != false {
    65  		t.Error("barrier isBroken, expected", false, ", got", isBroken)
    66  	}
    67  }
    68  
    69  func TestAwaitMany(t *testing.T) {
    70  	num := 100
    71  	m := 1000
    72  	b := New(num)
    73  	ctx := context.Background()
    74  	wg := sync.WaitGroup{}
    75  
    76  	for i := 0; i < num; i++ {
    77  		wg.Add(1)
    78  		go func() {
    79  			for j := 0; j < m; j++ {
    80  				err := b.Await(ctx)
    81  				if err != nil {
    82  					panic(err)
    83  				}
    84  			}
    85  			wg.Done()
    86  		}()
    87  	}
    88  
    89  	wg.Wait()
    90  
    91  	n, nWaiting := b.N(), b.NWaiting()
    92  	isBroken := b.IsBroken()
    93  
    94  	if n != num {
    95  		t.Error("number of barrier members, expected", num, ", got", n)
    96  	}
    97  	if nWaiting != 0 {
    98  		t.Error("number of barrier members waiting, expected", 0, ", got", nWaiting)
    99  	}
   100  	if isBroken != false {
   101  		t.Error("barrier isBroken, expected", false, ", got", isBroken)
   102  	}
   103  }
   104  
   105  func TestAwaitTooMany(t *testing.T) {
   106  	num := 100
   107  	m := 1000
   108  	b := New(1)
   109  	ctx := context.Background()
   110  	wg := sync.WaitGroup{}
   111  
   112  	for i := 0; i < num; i++ {
   113  		wg.Add(1)
   114  		go func() {
   115  			for j := 0; j < m; j++ {
   116  				err := b.Await(ctx)
   117  				if err != nil {
   118  					panic(err)
   119  				}
   120  			}
   121  			wg.Done()
   122  		}()
   123  	}
   124  
   125  	wg.Wait()
   126  
   127  	n, nWaiting := b.N(), b.NWaiting()
   128  	isBroken := b.IsBroken()
   129  
   130  	if n != 1 {
   131  		t.Error("number of barrier members, expected", num, ", got", n)
   132  	}
   133  	if nWaiting != 0 {
   134  		t.Error("number of barrier members waiting, expected", 0, ", got", nWaiting)
   135  	}
   136  	if isBroken != false {
   137  		t.Error("barrier isBroken, expected", false, ", got", isBroken)
   138  	}
   139  }
   140  
   141  func TestReset(t *testing.T) {
   142  	num := 100
   143  	b := New(num + 1) // members are more than goroutines so all goroutines will wait
   144  	ctx := context.Background()
   145  
   146  	go func() {
   147  		time.Sleep(30 * time.Millisecond)
   148  		b.Reset()
   149  	}()
   150  
   151  	wg := sync.WaitGroup{}
   152  	for i := 0; i < num; i++ {
   153  		wg.Add(1)
   154  		go func() {
   155  			err := b.Await(ctx)
   156  			if err != ErrBroken {
   157  				panic(err)
   158  			}
   159  			wg.Done()
   160  		}()
   161  	}
   162  
   163  	wg.Wait()
   164  
   165  	n, nWaiting := b.N(), b.NWaiting()
   166  	isBroken := b.IsBroken()
   167  
   168  	if n != num+1 {
   169  		t.Error("number of barrier members, expected", num+1, ", got", n)
   170  	}
   171  	if nWaiting != 0 {
   172  		t.Error("number of barrier members waiting, expected", 0, ", got", nWaiting)
   173  	}
   174  	if isBroken != false {
   175  		t.Error("barrier isBroken, expected", false, ", got", isBroken)
   176  	}
   177  }
   178  
   179  func TestAwaitOnceCtxDone(t *testing.T) {
   180  	num := 100
   181  	b := New(num + 1) // members are more than goroutines so all goroutines will wait
   182  	ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
   183  	defer cancel()
   184  	var deadlineCount, brokenBarrierCount int32
   185  	wg := sync.WaitGroup{}
   186  
   187  	for i := 0; i < num; i++ {
   188  		wg.Add(1)
   189  		go func() {
   190  			err := b.Await(ctx)
   191  			if err == context.DeadlineExceeded {
   192  				atomic.AddInt32(&deadlineCount, 1)
   193  			} else if err == ErrBroken {
   194  				atomic.AddInt32(&brokenBarrierCount, 1)
   195  			} else {
   196  				panic("must be either context.DeadlineExceeded or ErrBroken error")
   197  			}
   198  			wg.Done()
   199  		}()
   200  	}
   201  
   202  	wg.Wait()
   203  
   204  	n, nWaiting := b.N(), b.NWaiting()
   205  	isBroken := b.IsBroken()
   206  
   207  	if n != num+1 {
   208  		t.Error("number of barrier members, expected", num+1, ", got", n)
   209  	}
   210  	if nWaiting != 100 {
   211  		t.Error("number of barrier members waiting, expected", 100, ", got", nWaiting)
   212  	}
   213  	if isBroken != true {
   214  		t.Error("barrier isBroken, expected", true, ", got", isBroken)
   215  	}
   216  
   217  	if deadlineCount == 0 {
   218  		t.Error("number of context.DeadlineExceeded errors must be more than 0, got", deadlineCount)
   219  	}
   220  	if deadlineCount+brokenBarrierCount != int32(num) {
   221  		t.Error("number of context.DeadlineExceeded and ErrBroken errors, expected", num, ", got", deadlineCount+brokenBarrierCount)
   222  	}
   223  }
   224  
   225  func TestAwaitManyCtxDone(t *testing.T) {
   226  	num := 100
   227  	b := New(num)
   228  	ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
   229  	defer cancel()
   230  	wg := sync.WaitGroup{}
   231  
   232  	for i := 0; i < num; i++ {
   233  		wg.Add(1)
   234  		go func() {
   235  			for {
   236  				err := b.Await(ctx)
   237  				if err != nil {
   238  					if err != context.DeadlineExceeded && err != ErrBroken {
   239  						panic("must be either context.DeadlineExceeded or ErrBroken error")
   240  					}
   241  					break
   242  				}
   243  			}
   244  			wg.Done()
   245  		}()
   246  	}
   247  
   248  	wg.Wait()
   249  
   250  	n := b.N()
   251  	isBroken := b.IsBroken()
   252  
   253  	if n != num {
   254  		t.Error("number of barrier members, expected", num, ", got", n)
   255  	}
   256  	if isBroken != true {
   257  		t.Error("barrier isBroken, expected", true, ", got", isBroken)
   258  	}
   259  }