github.com/ttys3/engine@v17.12.1-ce-rc2+incompatible/pkg/locker/locker_test.go (about)

     1  package locker
     2  
     3  import (
     4  	"math/rand"
     5  	"strconv"
     6  	"sync"
     7  	"testing"
     8  	"time"
     9  )
    10  
    11  func TestLockCounter(t *testing.T) {
    12  	l := &lockCtr{}
    13  	l.inc()
    14  
    15  	if l.waiters != 1 {
    16  		t.Fatal("counter inc failed")
    17  	}
    18  
    19  	l.dec()
    20  	if l.waiters != 0 {
    21  		t.Fatal("counter dec failed")
    22  	}
    23  }
    24  
    25  func TestLockerLock(t *testing.T) {
    26  	l := New()
    27  	l.Lock("test")
    28  	ctr := l.locks["test"]
    29  
    30  	if ctr.count() != 0 {
    31  		t.Fatalf("expected waiters to be 0, got :%d", ctr.waiters)
    32  	}
    33  
    34  	chDone := make(chan struct{})
    35  	go func() {
    36  		l.Lock("test")
    37  		close(chDone)
    38  	}()
    39  
    40  	chWaiting := make(chan struct{})
    41  	go func() {
    42  		for range time.Tick(1 * time.Millisecond) {
    43  			if ctr.count() == 1 {
    44  				close(chWaiting)
    45  				break
    46  			}
    47  		}
    48  	}()
    49  
    50  	select {
    51  	case <-chWaiting:
    52  	case <-time.After(3 * time.Second):
    53  		t.Fatal("timed out waiting for lock waiters to be incremented")
    54  	}
    55  
    56  	select {
    57  	case <-chDone:
    58  		t.Fatal("lock should not have returned while it was still held")
    59  	default:
    60  	}
    61  
    62  	if err := l.Unlock("test"); err != nil {
    63  		t.Fatal(err)
    64  	}
    65  
    66  	select {
    67  	case <-chDone:
    68  	case <-time.After(3 * time.Second):
    69  		t.Fatalf("lock should have completed")
    70  	}
    71  
    72  	if ctr.count() != 0 {
    73  		t.Fatalf("expected waiters to be 0, got: %d", ctr.count())
    74  	}
    75  }
    76  
    77  func TestLockerUnlock(t *testing.T) {
    78  	l := New()
    79  
    80  	l.Lock("test")
    81  	l.Unlock("test")
    82  
    83  	chDone := make(chan struct{})
    84  	go func() {
    85  		l.Lock("test")
    86  		close(chDone)
    87  	}()
    88  
    89  	select {
    90  	case <-chDone:
    91  	case <-time.After(3 * time.Second):
    92  		t.Fatalf("lock should not be blocked")
    93  	}
    94  }
    95  
    96  func TestLockerConcurrency(t *testing.T) {
    97  	l := New()
    98  
    99  	var wg sync.WaitGroup
   100  	for i := 0; i <= 10000; i++ {
   101  		wg.Add(1)
   102  		go func() {
   103  			l.Lock("test")
   104  			// if there is a concurrency issue, will very likely panic here
   105  			l.Unlock("test")
   106  			wg.Done()
   107  		}()
   108  	}
   109  
   110  	chDone := make(chan struct{})
   111  	go func() {
   112  		wg.Wait()
   113  		close(chDone)
   114  	}()
   115  
   116  	select {
   117  	case <-chDone:
   118  	case <-time.After(10 * time.Second):
   119  		t.Fatal("timeout waiting for locks to complete")
   120  	}
   121  
   122  	// Since everything has unlocked this should not exist anymore
   123  	if ctr, exists := l.locks["test"]; exists {
   124  		t.Fatalf("lock should not exist: %v", ctr)
   125  	}
   126  }
   127  
   128  func BenchmarkLocker(b *testing.B) {
   129  	l := New()
   130  	for i := 0; i < b.N; i++ {
   131  		l.Lock("test")
   132  		l.Unlock("test")
   133  	}
   134  }
   135  
   136  func BenchmarkLockerParallel(b *testing.B) {
   137  	l := New()
   138  	b.SetParallelism(128)
   139  	b.RunParallel(func(pb *testing.PB) {
   140  		for pb.Next() {
   141  			l.Lock("test")
   142  			l.Unlock("test")
   143  		}
   144  	})
   145  }
   146  
   147  func BenchmarkLockerMoreKeys(b *testing.B) {
   148  	l := New()
   149  	var keys []string
   150  	for i := 0; i < 64; i++ {
   151  		keys = append(keys, strconv.Itoa(i))
   152  	}
   153  	b.SetParallelism(128)
   154  	b.RunParallel(func(pb *testing.PB) {
   155  		for pb.Next() {
   156  			k := keys[rand.Intn(len(keys))]
   157  			l.Lock(k)
   158  			l.Unlock(k)
   159  		}
   160  	})
   161  }