github.com/quay/claircore@v1.5.28/libvuln/updates/locks_test.go (about)

     1  package updates
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"sync"
     7  	"sync/atomic"
     8  	"testing"
     9  )
    10  
    11  func TestLocalLockUnlock(t *testing.T) {
    12  	ctx := context.Background()
    13  	l := NewLocalLockSource()
    14  
    15  	t.Log("lock")
    16  	c, done := l.Lock(ctx, t.Name())
    17  	if err := c.Err(); err != nil {
    18  		t.Error(err)
    19  	}
    20  	t.Log("unlock")
    21  	done()
    22  	if l.peek(t.Name()) {
    23  		t.Error("lock held")
    24  	}
    25  
    26  	t.Log("lock")
    27  	c, done = l.Lock(ctx, t.Name())
    28  	if err := c.Err(); err != nil {
    29  		t.Error(err)
    30  	}
    31  	t.Log("unlock")
    32  	done()
    33  	if l.peek(t.Name()) {
    34  		t.Error("lock held")
    35  	}
    36  }
    37  
    38  func TestLocalTryLock(t *testing.T) {
    39  	ctx := context.Background()
    40  	locks := NewLocalLockSource()
    41  	locked := make(chan struct{})
    42  	unlock := make(chan struct{})
    43  	unlocked := make(chan struct{})
    44  	go func() {
    45  		ctx, done := locks.Lock(ctx, t.Name())
    46  		if err := ctx.Err(); err != nil {
    47  			t.Error(err)
    48  		}
    49  		defer func() {
    50  			done()
    51  			close(unlocked)
    52  			t.Log("lock released")
    53  		}()
    54  		t.Log("lock held")
    55  		close(locked)
    56  		<-unlock
    57  	}()
    58  
    59  	<-locked
    60  	lc, done := locks.TryLock(ctx, t.Name())
    61  	t.Logf("try: %v", lc.Err())
    62  	if !errors.Is(lc.Err(), context.Canceled) {
    63  		t.Error("wanted TryLock to fail")
    64  	}
    65  	done()
    66  	close(unlock)
    67  	<-unlocked
    68  	lc, done = locks.TryLock(ctx, t.Name())
    69  	t.Logf("try: %v", lc.Err())
    70  	if !errors.Is(lc.Err(), nil) {
    71  		t.Error("wanted TryLock to succeed")
    72  	}
    73  	done()
    74  	t.Log("unlocked")
    75  }
    76  
    77  func TestLocalLockSequential(t *testing.T) {
    78  	ctx := context.Background()
    79  	locks := NewLocalLockSource()
    80  	var wg sync.WaitGroup
    81  	wg.Add(2)
    82  	var ct uint64
    83  	_, d1 := locks.Lock(ctx, t.Name())
    84  	go func() {
    85  		_, d2 := locks.Lock(ctx, t.Name())
    86  		defer func() {
    87  			d2()
    88  			wg.Done()
    89  		}()
    90  		t.Log("1 → 2")
    91  		if !atomic.CompareAndSwapUint64(&ct, 1, 2) {
    92  			t.Error("ordering error")
    93  		}
    94  	}()
    95  	go func() {
    96  		defer func() {
    97  			d1()
    98  			wg.Done()
    99  		}()
   100  		t.Log("0 → 1")
   101  		if !atomic.CompareAndSwapUint64(&ct, 0, 1) {
   102  			t.Error("ordering error")
   103  		}
   104  	}()
   105  
   106  	wg.Wait()
   107  	if got, want := ct, uint64(2); got != want {
   108  		t.Errorf("got: %d, want: %d", got, want)
   109  	}
   110  }