test: handle unsupported catalog clients in S3 Tables CI (#12023)

test: distinguish unsupported catalog clients from S3 Tables failures
This commit is contained in:
Chris Lu authored and GitHub committed 2026-10-23 22:40:54 -07:00
1 parent aba0cb7b2a
commit a1b3131bf6
9 files changed
+91 -1

No files matched your search

@@ -115,6 +115,9 @@ SELECT 'duckdb deterministic-location describe ok' AS marker;
t.Logf("DuckDB output:\n%s", outputStr)
if err != nil {
if testutil.IsIllegalInstruction(err) {
t.Skipf("DuckDB image cannot run on this CPU: %v", err)
}
// Tolerate environments where the Iceberg extension/version is too
// limited to exercise this code path. The intent is to gain
// coverage where it's available, not to require it everywhere.
@@ -351,6 +351,9 @@ SELECT 'DuckDB Iceberg OAuth secret created successfully' as result;
t.Logf("DuckDB output:\n%s", outputStr)
if err != nil {
if testutil.IsIllegalInstruction(err) {
t.Skipf("DuckDB image cannot run on this CPU: %v", err)
}
if strings.Contains(outputStr, "iceberg extension is not available") ||
strings.Contains(outputStr, "Failed to load") {
t.Skip("Skipping: Iceberg extension not available in DuckDB Docker image")
@@ -379,6 +382,9 @@ SELECT 'DuckDB Iceberg OAuth secret created successfully' as result;
t.Logf("DuckDB fallback output:\n%s", fallbackStr)
if fallbackErr != nil {
if testutil.IsIllegalInstruction(fallbackErr) {
t.Skipf("DuckDB image cannot run on this CPU: %v", fallbackErr)
}
if strings.Contains(fallbackStr, "NotFound_404") && strings.Contains(fallbackStr, "/v1/oauth/tokens") {
t.Fatal("OAuth token endpoint returned 404 - the fix is not working")
}
@@ -574,6 +574,9 @@ SELECT 'Iceberg extension loaded successfully' as result;
output, err := cmd.CombinedOutput()
if err != nil {
t.Logf("DuckDB output: %s", output)
if testutil.IsIllegalInstruction(err) {
t.Skipf("DuckDB image cannot run on this CPU: %v", err)
}
// Check for expected errors in certain CI environments
outputStr := string(output)
if strings.Contains(outputStr, "iceberg extension is not available") ||
+3
View File
@@ -218,6 +218,9 @@ SELECT * FROM test_catalog.%s.%s LIMIT 0;
}
if runErr != nil {
if testutil.IsIllegalInstruction(runErr) {
t.Skipf("DuckDB image cannot run on this CPU: %v", runErr)
}
if strings.Contains(outStr, "does not exist because schema") &&
strings.Contains(outStr, namespace) {
t.Fatalf("reproduced issue #9103: DuckDB cannot see namespace %q after ATTACH 's3://%s/'; see output above",
+6 -1
View File
@@ -2,11 +2,13 @@ package catalog
import (
"fmt"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3tables"
"os"
"os/exec"
"path/filepath"
"testing"
"github.com/seaweedfs/seaweedfs/test/testutil"
"github.com/seaweedfs/seaweedfs/weed/s3api/s3tables"
)
// TestLanceNamespaceRealClient drives the namespace with the Lance client rather
@@ -58,6 +60,9 @@ func TestLanceNamespaceRealClient(t *testing.T) {
t.Logf("Running Lance client test against %s", namespaceURL)
if err := cmd.Run(); err != nil {
if testutil.IsIllegalInstruction(err) {
t.Skipf("Lance client image cannot run on this CPU: %v", err)
}
t.Errorf("Lance client test failed: %v", err)
}
}
@@ -272,6 +272,9 @@ func (env *environment) runClient(t *testing.T, bucket string) {
out, err := cmd.CombinedOutput()
t.Logf("LanceDB client output:\n%s", out)
if err != nil {
if testutil.IsIllegalInstruction(err) {
t.Skipf("LanceDB client image cannot run on this CPU: %v", err)
}
t.Fatalf("the LanceDB client failed: %v", err)
}
if !strings.Contains(string(out), "PASS") {
@@ -194,6 +194,7 @@ func (env *TestEnvironment) StartRisingWave(t *testing.T) {
if output, err := cmd.CombinedOutput(); err != nil {
t.Fatalf("failed to start RisingWave container: %v\n%s", err, string(output))
}
env.checkRisingWaveContainer(t)
// Start a sidecar postgres container for running psql commands
sidecarName := "seaweed-risingwave-sidecar-" + randomString(8)
@@ -205,6 +206,7 @@ func (env *TestEnvironment) StartRisingWave(t *testing.T) {
"sleep", "infinity",
)
if output, err := sidecarCmd.CombinedOutput(); err != nil {
env.checkRisingWaveContainer(t)
t.Fatalf("failed to start postgres sidecar: %v\n%s", err, string(output))
}
@@ -220,6 +222,7 @@ func (env *TestEnvironment) waitForRisingWave(timeout time.Duration) bool {
deadline := time.Now().Add(timeout)
env.t.Logf(">>> Waiting for RisingWave to be ready (timeout %v)...\n", timeout)
for time.Now().Before(deadline) {
env.checkRisingWaveContainer(env.t)
if output, err := runPostgresClientSQL(env.postgresSidecar, "SELECT 1;"); err == nil {
env.t.Logf(">>> RisingWave is ready.\n")
return true
@@ -231,6 +234,26 @@ func (env *TestEnvironment) waitForRisingWave(timeout time.Duration) bool {
return false
}
func (env *TestEnvironment) checkRisingWaveContainer(t *testing.T) {
t.Helper()
out, err := exec.Command("docker", "inspect", "--format", "{{.State.Running}} {{.State.ExitCode}} {{.State.OOMKilled}}", env.risingwaveContainer).CombinedOutput()
if err != nil {
t.Fatalf("inspect RisingWave container: %v\n%s", err, out)
}
state := strings.Fields(string(out))
if len(state) != 3 {
t.Fatalf("unexpected RisingWave container state: %s", out)
}
if state[0] == "true" {
return
}
if state[1] == "132" && state[2] == "false" {
t.Skip("RisingWave image exited with illegal instruction on this CPU")
}
logs, _ := exec.Command("docker", "logs", env.risingwaveContainer).CombinedOutput()
t.Fatalf("RisingWave container exited before it became ready (code %s, OOM killed: %s):\n%s", state[1], state[2], logs)
}
func runPostgresClientSQL(containerName, sql string) ([]byte, error) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
+5
View File
@@ -51,6 +51,11 @@ func RequireImageRunnable(t *testing.T, args ...string) {
}
}
func IsIllegalInstruction(err error) bool {
var exitErr *exec.ExitError
return errors.As(err, &exitErr) && exitErr.ExitCode() == 132
}
func FindBindIP() string {
addrs, err := net.InterfaceAddrs()
if err != nil {
+39
View File
@@ -0,0 +1,39 @@
package testutil
import (
"errors"
"fmt"
"os"
"os/exec"
"strconv"
"testing"
)
func TestIsIllegalInstruction(t *testing.T) {
if code := os.Getenv("SEAWEEDFS_TEST_EXIT_CODE"); code != "" {
status, _ := strconv.Atoi(code)
os.Exit(status)
}
for _, tc := range []struct {
name string
code string
want bool
}{
{"illegal instruction", "132", true},
{"ordinary failure", "1", false},
{"out of memory", "137", false},
} {
t.Run(tc.name, func(t *testing.T) {
cmd := exec.Command(os.Args[0], "-test.run=^TestIsIllegalInstruction$")
cmd.Env = append(os.Environ(), "SEAWEEDFS_TEST_EXIT_CODE="+tc.code)
err := cmd.Run()
if got := IsIllegalInstruction(fmt.Errorf("docker run: %w", err)); got != tc.want {
t.Fatalf("IsIllegalInstruction(%v) = %v, want %v", err, got, tc.want)
}
})
}
if IsIllegalInstruction(nil) || IsIllegalInstruction(errors.New("exit status 132")) {
t.Fatal("non-process errors must not be treated as illegal instructions")
}
}