github.com/quay/claircore@v1.5.28/test/integration/lock_unix.go (about)

     1  //go:build !windows
     2  
     3  package integration
     4  
     5  import (
     6  	"os"
     7  	"syscall"
     8  	"testing"
     9  )
    10  
    11  /*
    12  Code below does some shenanigans to lock the directory that we extract to. This
    13  has to be done because the `go test` will run package tests in parallel, so
    14  different packages may see the extracted binaries in various states if there
    15  was not any synchronization. We use an exclusive flock(2) as a write lock, and
    16  obtain a shared lock as a read gate.
    17  
    18  Without this, tests would flake on a cold cache.
    19  */
    20  
    21  func lockDir(t testing.TB, dir string) (excl bool) {
    22  	t.Helper()
    23  	lf, err := os.Open(dir)
    24  	if err != nil {
    25  		t.Fatal(err)
    26  	}
    27  	fd := int(lf.Fd())
    28  	t.Cleanup(func() {
    29  		if err := syscall.Flock(fd, syscall.LOCK_UN); err != nil {
    30  			t.Error(err)
    31  		}
    32  		if err := lf.Close(); err != nil {
    33  			t.Error(err)
    34  		}
    35  	})
    36  	if err := syscall.Flock(fd, syscall.LOCK_EX|syscall.LOCK_NB); err != nil {
    37  		// Failed to lock, wait for a shared lock, then return
    38  		t.Logf("waiting for lock on %q", dir)
    39  		if err := syscall.Flock(fd, syscall.LOCK_SH); err != nil {
    40  			t.Fatal(err)
    41  		}
    42  		return false
    43  	}
    44  	return true
    45  }
    46  
    47  func lockDirShared(t testing.TB, dir string) {
    48  	t.Helper()
    49  	lf, err := os.Open(dir)
    50  	if err != nil {
    51  		t.Fatal(err)
    52  	}
    53  	t.Cleanup(func() {
    54  		if err := lf.Close(); err != nil {
    55  			t.Error(err)
    56  		}
    57  	})
    58  	if err := syscall.Flock(int(lf.Fd()), syscall.LOCK_SH); err != nil {
    59  		t.Fatal(err)
    60  	}
    61  }