diff --git a/test/integration/db_init.go b/test/integration/db_init.go index 57b5ce388..770f12d4f 100644 --- a/test/integration/db_init.go +++ b/test/integration/db_init.go @@ -3,8 +3,6 @@ package integration import ( "os" "runtime" - "strings" - "syscall" ) var ( @@ -32,44 +30,6 @@ func init() { dbVersion = v9 } - // See if we need to fix up the Arch name. - switch dbOS { - // the zonkyio/embedded-postgres-binaries project produces - // arm binaries with the following name schema: - // 32bit: arm32v6 / arm32v7 - // 64bit (aarch64): arm64v8 - case "linux": - switch dbArch { - case "arm64": - dbArch += "v8" - case "arm": - var u syscall.Utsname - if err := syscall.Uname(&u); err != nil { - panic(err) - } - t := make([]byte, 0, len(u.Machine[:])) - for _, b := range u.Machine[:] { - if b == 0 { - break - } - t = append(t, byte(b)) - } - mach := strings.TrimRight(string(t), "\x00") - switch { - case strings.HasPrefix(mach, "armv7"): - dbArch += "32v7" - case strings.HasPrefix(mach, "armv6"): - dbArch += "32v6" - } - } - // if on alpine - if _, err := os.Stat("/etc/alpine-release"); err == nil { - dbArch += "-alpine" - } - case "darwin": - switch dbArch { - case "arm64": // No arm build yet, so use the emulator. - dbArch = "amd64" - } - } + // This is a per-OS function. + fixupName(&dbArch) } diff --git a/test/integration/engine.go b/test/integration/engine.go index 41edae66a..bb146d56d 100644 --- a/test/integration/engine.go +++ b/test/integration/engine.go @@ -14,7 +14,6 @@ import ( "path/filepath" "strconv" "strings" - "syscall" "testing" "github.com/ulikunitz/xz" @@ -103,33 +102,12 @@ func (e *Engine) Stop() error { return cmd.Run() } -/* -Code below does some shenanigans to lock the directory that we extract to. This -has to be done because the `go test` will run package tests in parallel, so -different packages may see the extracted binaries in various states if there -was not any synchronization. We use an exclusive flock(2) as a write lock, and -obtain a shared lock as a read gate. - -Without this, tests would flake on a cold cache. -*/ - func fetchArchive(t testing.TB) { p, err := cachedDir() if errors.Is(err, os.ErrNotExist) { os.MkdirAll(p, 0755) } - lf, err := os.Open(p) - if err != nil { - t.Fatal(err) - } - defer lf.Close() - defer syscall.Flock(int(lf.Fd()), syscall.LOCK_UN) - if err := syscall.Flock(int(lf.Fd()), syscall.LOCK_EX|syscall.LOCK_NB); err != nil { - // Failed to lock, wait for a shared lock, then return - t.Log("waiting for another process to fetch binaries") - if err := syscall.Flock(int(lf.Fd()), syscall.LOCK_SH); err != nil { - t.Fatal(err) - } + if !lockDir(t, p) { return } @@ -256,14 +234,7 @@ func binUncached(t testing.TB) bool { // If it does exist, wait until we can grab a shared lock. If this blocks, // it's because another process has the exclusive (write) lock. Any error // during this process just fails the test. - lf, err := os.Open(p) - if err != nil { - t.Fatal(err) - } - defer lf.Close() - if err := syscall.Flock(int(lf.Fd()), syscall.LOCK_SH); err != nil { - t.Fatal(err) - } + lockDirShared(t, p) return false } diff --git a/test/integration/fixup_darwin.go b/test/integration/fixup_darwin.go new file mode 100644 index 000000000..44df5e7b9 --- /dev/null +++ b/test/integration/fixup_darwin.go @@ -0,0 +1,8 @@ +package integration + +func fixupName(dbArch *string) { + // No arm build yet, so use the emulator. + if *dbArch == "arm64" { + *dbArch = "amd64" + } +} diff --git a/test/integration/fixup_linux.go b/test/integration/fixup_linux.go new file mode 100644 index 000000000..10bf0a02d --- /dev/null +++ b/test/integration/fixup_linux.go @@ -0,0 +1,42 @@ +package integration + +import ( + "os" + "strings" + "syscall" +) + +// the zonkyio/embedded-postgres-binaries project produces +// arm binaries with the following name schema: +// 32bit: arm32v6 / arm32v7 +// 64bit (aarch64): arm64v8 + +func fixupName(dbArch *string) { + switch *dbArch { + case "arm64": + *dbArch += "v8" + case "arm": + var u syscall.Utsname + if err := syscall.Uname(&u); err != nil { + panic(err) + } + t := make([]byte, 0, len(u.Machine[:])) + for _, b := range u.Machine[:] { + if b == 0 { + break + } + t = append(t, byte(b)) + } + mach := strings.TrimRight(string(t), "\x00") + switch { + case strings.HasPrefix(mach, "armv7"): + *dbArch += "32v7" + case strings.HasPrefix(mach, "armv6"): + *dbArch += "32v6" + } + } + // if on alpine + if _, err := os.Stat("/etc/alpine-release"); err == nil { + *dbArch += "-alpine" + } +} diff --git a/test/integration/fixup_other.go b/test/integration/fixup_other.go new file mode 100644 index 000000000..b25ce9718 --- /dev/null +++ b/test/integration/fixup_other.go @@ -0,0 +1,6 @@ +//go:build !darwin && !linux +// +build !darwin,!linux + +package integration + +func fixupName(_ *string) {} diff --git a/test/integration/lock_unix.go b/test/integration/lock_unix.go new file mode 100644 index 000000000..45420502e --- /dev/null +++ b/test/integration/lock_unix.go @@ -0,0 +1,60 @@ +//go:build !windows +// +build !windows + +package integration + +import ( + "os" + "syscall" + "testing" +) + +/* +Code below does some shenanigans to lock the directory that we extract to. This +has to be done because the `go test` will run package tests in parallel, so +different packages may see the extracted binaries in various states if there +was not any synchronization. We use an exclusive flock(2) as a write lock, and +obtain a shared lock as a read gate. + +Without this, tests would flake on a cold cache. +*/ + +func lockDir(t testing.TB, dir string) (excl bool) { + lf, err := os.Open(dir) + if err != nil { + t.Fatal(err) + } + fd := int(lf.Fd()) + t.Cleanup(func() { + if err := syscall.Flock(fd, syscall.LOCK_UN); err != nil { + t.Error(err) + } + if err := lf.Close(); err != nil { + t.Error(err) + } + }) + if err := syscall.Flock(fd, syscall.LOCK_EX|syscall.LOCK_NB); err != nil { + // Failed to lock, wait for a shared lock, then return + t.Logf("waiting for lock on %q", dir) + if err := syscall.Flock(fd, syscall.LOCK_SH); err != nil { + t.Fatal(err) + } + return false + } + return true +} + +func lockDirShared(t testing.TB, dir string) { + lf, err := os.Open(dir) + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + if err := lf.Close(); err != nil { + t.Error(err) + } + }) + if err := syscall.Flock(int(lf.Fd()), syscall.LOCK_SH); err != nil { + t.Fatal(err) + } +} diff --git a/test/integration/lock_windows.go b/test/integration/lock_windows.go new file mode 100644 index 000000000..c5f7b27f5 --- /dev/null +++ b/test/integration/lock_windows.go @@ -0,0 +1,12 @@ +package integration + +import "testing" + +// BUG(hank) The windows implementation of the file locking is non-fuctional. We +// only build the clair client binaries on windows, so this shouldn't matter. +// If anyone wants to actually run clair on windows, this should be fixed so +// that the tests don't flake. + +func lockDir(_ testing.TB, _ string) (excl bool) { return true } + +func lockDirShared(_ testing.TB, _ string) {} diff --git a/test/integration/run.go b/test/integration/run.go index 28db15dde..0a5237770 100644 --- a/test/integration/run.go +++ b/test/integration/run.go @@ -1,3 +1,4 @@ +//go:build integration // +build integration package integration diff --git a/test/integration/skip.go b/test/integration/skip.go index 439e1f525..38a7f2829 100644 --- a/test/integration/skip.go +++ b/test/integration/skip.go @@ -1,3 +1,4 @@ +//go:build !integration // +build !integration package integration