test: skip catalog client images that cannot execute on the host CPU (#12014)

New upstream releases build for x86-64-v3 (AVX2) - ClickHouse since
26.5, plus the DuckDB iceberg extension and pylance wheels - so on a
runner whose CPU lacks AVX2 the container dies on SIGILL before the
test reaches any SeaweedFS code. Probe each third-party image first
and skip on the illegal-instruction exit instead of failing; other
errors still surface normally.
This commit is contained in:
Chris Lu authored and GitHub committed 2026-10-23 18:46:26 -07:00
1 parent 0d4e11a6e5
commit 462e4445e2
4 files changed
+49

No files matched your search

@@ -871,6 +871,11 @@ func requireClickHouseRuntime(t *testing.T) {
if !hasDocker() {
t.Skip("Docker not available, skipping ClickHouse integration test")
}
// ClickHouse builds for x86-64-v3 (AVX2) since 26.5; on a CPU without it
// the binary dies on SIGILL inside the entrypoint before the server can
// come up.
testutil.RequireImageRunnable(t,
"--entrypoint", "clickhouse", clickhouseImage(), "local", "--query", "SELECT 1")
}
// hasDocker reports whether `docker version` can run, which we treat as a
@@ -70,6 +70,13 @@ func TestIcebergTableLifecycle(t *testing.T) {
func testIcebergLifecycleWithDuckDB(t *testing.T) {
env := shared
// The write phase's first act is INSTALLing the iceberg extension, whose
// binary can itself target a newer x86-64 baseline than the host CPU has.
testutil.RequireImageRunnable(t,
"--entrypoint", "duckdb", duckdbImage,
"-c", "INSTALL iceberg; LOAD iceberg; SELECT 1;")
bucket := "lifecycle-duckdb-" + randomSuffix()
namespace, table := "sales", "events"
env.createTableBucket(t, bucket, "ICEBERG")
@@ -109,6 +116,9 @@ func testIcebergLifecycleWithPyIceberg(t *testing.T) {
namespace, table := "sales", "events"
env.createTableBucket(t, bucket, "ICEBERG")
buildClientImage(t, pyicebergImage, "Dockerfile.pyiceberg")
testutil.RequireImageRunnable(t,
"--entrypoint", "python3", pyicebergImage,
"-c", "import pyarrow; from pyiceberg.catalog import load_catalog")
before := env.pyiceberg(t, "write", bucket, namespace, table)
assertSeeded(t, before)
@@ -35,6 +35,9 @@ func TestLanceTableLifecycle(t *testing.T) {
namespace, table := "ml", "events"
env.createTableBucket(t, bucket, "LANCE")
buildClientImage(t, lanceImage, "Dockerfile.lance")
testutil.RequireImageRunnable(t,
"--entrypoint", "python3", lanceImage,
"-c", "import lance; import lance_namespace; import pyarrow")
before := env.lance(t, "write", bucket, namespace, table)
assertSeeded(t, before)
+31
View File
@@ -2,12 +2,15 @@ package testutil
import (
"context"
"errors"
"fmt"
"net"
"net/http"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"time"
)
@@ -20,6 +23,34 @@ func HasDocker() bool {
return cmd.Run() == nil
}
// RequireImageRunnable runs a throwaway container with the given `docker run`
// arguments and skips the test when its process dies on SIGILL. Upstream
// images increasingly target x86-64-v3 (AVX2) - ClickHouse since 26.5 - so a
// host CPU without those instructions cannot run them at all, and the failure
// says nothing about the code under test. Any other outcome, whether a clean
// run, an ordinary non-zero exit, or a pull failure, is left for the test
// itself to report: the probe can only skip on the one failure the code
// cannot cause.
func RequireImageRunnable(t *testing.T, args ...string) {
t.Helper()
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
cmd := exec.CommandContext(ctx, "docker", append([]string{"run", "--rm"}, args...)...)
out, err := cmd.CombinedOutput()
if err == nil {
return
}
var exitErr *exec.ExitError
// 132 = 128 + SIGILL: docker propagates the container process's death.
if errors.As(err, &exitErr) &&
(exitErr.ExitCode() == 132 ||
strings.Contains(string(out), "Illegal instruction")) {
t.Skipf("image cannot execute on this CPU (illegal instruction): docker run %s\n%s",
strings.Join(args, " "), out)
}
}
func FindBindIP() string {
addrs, err := net.InterfaceAddrs()
if err != nil {