Skip to content

Commit

Permalink
integration: multiple OS support
Browse files Browse the repository at this point in the history
Some linux-specific usage of the syscall package was added with the
embedded postgres addition. This splits out and cordons off all the
syscall usage so that this package builds on linux, darwin, and windows
again.

This backports #418

Signed-off-by: Hank Donnay <[email protected]>
  • Loading branch information
hdonnay committed Jul 26, 2021
1 parent bbafc5c commit 81f8501
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 73 deletions.
44 changes: 2 additions & 42 deletions test/integration/db_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package integration
import (
"os"
"runtime"
"strings"
"syscall"
)

var (
Expand Down Expand Up @@ -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)
}
33 changes: 2 additions & 31 deletions test/integration/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"path/filepath"
"strconv"
"strings"
"syscall"
"testing"

"github.com/ulikunitz/xz"
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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
}

Expand Down
8 changes: 8 additions & 0 deletions test/integration/fixup_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package integration

func fixupName(dbArch *string) {
// No arm build yet, so use the emulator.
if *dbArch == "arm64" {
*dbArch = "amd64"
}
}
42 changes: 42 additions & 0 deletions test/integration/fixup_linux.go
Original file line number Diff line number Diff line change
@@ -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"
}
}
6 changes: 6 additions & 0 deletions test/integration/fixup_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
//go:build !darwin && !linux
// +build !darwin,!linux

package integration

func fixupName(_ *string) {}
60 changes: 60 additions & 0 deletions test/integration/lock_unix.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
12 changes: 12 additions & 0 deletions test/integration/lock_windows.go
Original file line number Diff line number Diff line change
@@ -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) {}
1 change: 1 addition & 0 deletions test/integration/run.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build integration
// +build integration

package integration
Expand Down
1 change: 1 addition & 0 deletions test/integration/skip.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build !integration
// +build !integration

package integration
Expand Down

0 comments on commit 81f8501

Please sign in to comment.