Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

windows: more test / testutils fixups #1708

Merged
merged 3 commits into from
Mar 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ jobs:
GOMODCACHE: D:\gomodcache
# Avoid putting temp on slow C:
TEMP: D:\temp
CI_EFW_VERSION: "0.20.0"

steps:
- run: mkdir D:\temp
Expand Down
28 changes: 14 additions & 14 deletions info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,48 +105,48 @@ func TestProgramInfo(t *testing.T) {
qt.Assert(t, qt.IsTrue(ok))
qt.Assert(t, qt.Not(qt.Equals(id, 0)))

if testutils.IsKernelLessThan(t, "4.15") {
if testutils.IsVersionLessThan(t, "4.15") {
qt.Assert(t, qt.Equals(info.Name, ""))
} else {
qt.Assert(t, qt.Equals(info.Name, "test"))
}

if jitedSize, err := info.JitedSize(); testutils.IsKernelLessThan(t, "4.13") {
if jitedSize, err := info.JitedSize(); testutils.IsVersionLessThan(t, "4.13") {
qt.Assert(t, qt.IsNotNil(err))
} else {
qt.Assert(t, qt.IsNil(err))
qt.Assert(t, qt.IsTrue(jitedSize > 0))
}

if xlatedSize, err := info.TranslatedSize(); testutils.IsKernelLessThan(t, "4.13") {
if xlatedSize, err := info.TranslatedSize(); testutils.IsVersionLessThan(t, "4.13") {
qt.Assert(t, qt.IsNotNil(err))
} else {
qt.Assert(t, qt.IsNil(err))
qt.Assert(t, qt.IsTrue(xlatedSize > 0))
}

if uid, ok := info.CreatedByUID(); testutils.IsKernelLessThan(t, "4.15") {
if uid, ok := info.CreatedByUID(); testutils.IsVersionLessThan(t, "4.15") {
qt.Assert(t, qt.IsFalse(ok))
} else {
qt.Assert(t, qt.IsTrue(ok))
qt.Assert(t, qt.Equals(uid, uint32(os.Getuid())))
}

if loadTime, ok := info.LoadTime(); testutils.IsKernelLessThan(t, "4.15") {
if loadTime, ok := info.LoadTime(); testutils.IsVersionLessThan(t, "4.15") {
qt.Assert(t, qt.IsFalse(ok))
} else {
qt.Assert(t, qt.IsTrue(ok))
qt.Assert(t, qt.IsTrue(loadTime > 0))
}

if verifiedInsns, ok := info.VerifiedInstructions(); testutils.IsKernelLessThan(t, "5.16") {
if verifiedInsns, ok := info.VerifiedInstructions(); testutils.IsVersionLessThan(t, "5.16") {
qt.Assert(t, qt.IsFalse(ok))
} else {
qt.Assert(t, qt.IsTrue(ok))
qt.Assert(t, qt.IsTrue(verifiedInsns > 0))
}

if insns, ok := info.JitedInsns(); testutils.IsKernelLessThan(t, "4.13") {
if insns, ok := info.JitedInsns(); testutils.IsVersionLessThan(t, "4.13") {
qt.Assert(t, qt.IsFalse(ok))
} else {
qt.Assert(t, qt.IsTrue(ok))
Expand Down Expand Up @@ -175,28 +175,28 @@ func TestProgramInfoBTF(t *testing.T) {

// On kernels before 5.x, nr_jited_ksyms is not set for programs without subprogs.
// It's included here since this test uses a bpf program with subprogs.
if addrs, ok := info.JitedKsymAddrs(); testutils.IsKernelLessThan(t, "4.18") {
if addrs, ok := info.JitedKsymAddrs(); testutils.IsVersionLessThan(t, "4.18") {
qt.Assert(t, qt.IsFalse(ok))
} else {
qt.Assert(t, qt.IsTrue(ok))
qt.Assert(t, qt.IsTrue(len(addrs) > 0))
}

if lens, ok := info.JitedFuncLens(); testutils.IsKernelLessThan(t, "4.18") {
if lens, ok := info.JitedFuncLens(); testutils.IsVersionLessThan(t, "4.18") {
qt.Assert(t, qt.IsFalse(ok))
} else {
qt.Assert(t, qt.IsTrue(ok))
qt.Assert(t, qt.IsTrue(len(lens) > 0))
}

if infos, ok := info.JitedLineInfos(); testutils.IsKernelLessThan(t, "5.0") {
if infos, ok := info.JitedLineInfos(); testutils.IsVersionLessThan(t, "5.0") {
qt.Assert(t, qt.IsFalse(ok))
} else {
qt.Assert(t, qt.IsTrue(ok))
qt.Assert(t, qt.IsTrue(len(infos) > 0))
}

if funcs, err := info.FuncInfos(); testutils.IsKernelLessThan(t, "5.0") {
if funcs, err := info.FuncInfos(); testutils.IsVersionLessThan(t, "5.0") {
qt.Assert(t, qt.IsNotNil(err))
} else {
qt.Assert(t, qt.IsNil(err))
Expand All @@ -205,7 +205,7 @@ func TestProgramInfoBTF(t *testing.T) {
qt.Assert(t, qt.ContentEquals(funcs[1].Func, btfFn))
}

if lines, err := info.LineInfos(); testutils.IsKernelLessThan(t, "5.0") {
if lines, err := info.LineInfos(); testutils.IsVersionLessThan(t, "5.0") {
qt.Assert(t, qt.IsNotNil(err))
} else {
qt.Assert(t, qt.IsNil(err))
Expand Down Expand Up @@ -234,7 +234,7 @@ func TestProgramInfoMapIDs(t *testing.T) {

ids, ok := info.MapIDs()
switch {
case testutils.IsKernelLessThan(t, "4.15"):
case testutils.IsVersionLessThan(t, "4.15"):
qt.Assert(t, qt.IsFalse(ok))
qt.Assert(t, qt.HasLen(ids, 0))

Expand All @@ -259,7 +259,7 @@ func TestProgramInfoMapIDsNoMaps(t *testing.T) {

ids, ok := info.MapIDs()
switch {
case testutils.IsKernelLessThan(t, "4.15"):
case testutils.IsVersionLessThan(t, "4.15"):
qt.Assert(t, qt.IsFalse(ok))
qt.Assert(t, qt.HasLen(ids, 0))

Expand Down
36 changes: 10 additions & 26 deletions internal/feature.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"errors"
"fmt"
"runtime"
"strings"
"sync"

"github.com/cilium/ebpf/internal/platform"
Expand Down Expand Up @@ -76,40 +75,25 @@ type FeatureTestFn func() error
// Linux. Returns [ErrNotSupportedOnOS] if there is no version specified for the
// current OS.
func NewFeatureTest(name string, fn FeatureTestFn, versions ...string) func() error {
const nativePrefix = runtime.GOOS + ":"

if len(versions) == 0 {
return func() error {
return fmt.Errorf("feature test %q: no versions specified", name)
}
}

ft := &FeatureTest{
Name: name,
Fn: fn,
}

for _, version := range versions {
if strings.HasPrefix(version, nativePrefix) {
ft.Version = strings.TrimPrefix(version, nativePrefix)
break
}

if platform.IsLinux && !strings.ContainsRune(version, ':') {
// Allow version numbers without a GOOS prefix on Linux.
ft.Version = version
break
}
version, err := platform.SelectVersion(versions)
if err != nil {
return func() error { return err }
}

if ft.Version == "" {
if version == "" {
return func() error {
// We don't return an UnsupportedFeatureError here, since that will
// trigger version checks which don't make sense.
return fmt.Errorf("%s: %w", name, ErrNotSupportedOnOS)
}
}

ft := &FeatureTest{
Name: name,
Version: version,
Fn: fn,
}

return ft.execute
}

Expand Down
31 changes: 30 additions & 1 deletion internal/platform/platform.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package platform

import "runtime"
import (
"errors"
"runtime"
"strings"
)

const (
Linux = "linux"
Expand All @@ -10,3 +14,28 @@ const (
IsLinux = runtime.GOOS == "linux"
IsWindows = runtime.GOOS == "windows"
)

// SelectVersion extracts the platform-appropriate version from a list of strings like
// `linux:6.1` or `windows:0.20.0`.
//
// Returns an empty string and nil if no version matched or an error if no strings were passed.
func SelectVersion(versions []string) (string, error) {
const prefix = runtime.GOOS + ":"

if len(versions) == 0 {
return "", errors.New("no versions specified")
}

for _, version := range versions {
if strings.HasPrefix(version, prefix) {
return strings.TrimPrefix(version, prefix), nil
}

if IsLinux && !strings.ContainsRune(version, ':') {
// Allow version numbers without a GOOS prefix on Linux.
return version, nil
}
}

return "", nil
}
20 changes: 20 additions & 0 deletions internal/testutils/fd_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//go:build !windows

package testutils

import (
"testing"

"github.com/go-quicktest/qt"

"github.com/cilium/ebpf/internal/unix"
)

func DupFD(tb testing.TB, fd int) int {
tb.Helper()

dup, err := unix.FcntlInt(uintptr(fd), unix.F_DUPFD_CLOEXEC, 1)
qt.Assert(tb, qt.IsNil(err))

return dup
}
17 changes: 17 additions & 0 deletions internal/testutils/fd_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package testutils

import (
"testing"

"github.com/cilium/ebpf/internal/efw"
"github.com/go-quicktest/qt"
)

func DupFD(tb testing.TB, fd int) int {
tb.Helper()

dup, err := efw.EbpfDuplicateFd(fd)
qt.Assert(tb, qt.IsNil(err))

return dup
}
24 changes: 14 additions & 10 deletions internal/testutils/feature.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"strings"
"testing"

"github.com/go-quicktest/qt"

"github.com/cilium/ebpf/internal"
"github.com/cilium/ebpf/internal/platform"
)
Expand Down Expand Up @@ -104,25 +106,27 @@ func SkipOnOldKernel(tb testing.TB, minVersion, feature string) {
return
}

if IsKernelLessThan(tb, minVersion) {
if IsVersionLessThan(tb, minVersion) {
tb.Skipf("Test requires at least kernel %s (due to missing %s)", minVersion, feature)
}
}

// Check whether the running Linux version is smaller than a specific version.
//
// Warning: this function always returns false on platforms other than Linux.
func IsKernelLessThan(tb testing.TB, minVersion string) bool {
// Check whether the current runtime version is less than some minimum.
func IsVersionLessThan(tb testing.TB, minVersions ...string) bool {
tb.Helper()

if !platform.IsLinux {
tb.Logf("Ignoring version constraint %s on %s", minVersion, runtime.GOOS)
return false
version, err := platform.SelectVersion(minVersions)
qt.Assert(tb, qt.IsNil(err))

if version == "" {
// No matching version means that the platform
// doesn't support whatever feature.
return true
}

minv, err := internal.NewVersion(minVersion)
minv, err := internal.NewVersion(version)
if err != nil {
tb.Fatalf("Invalid version %s: %s", minVersion, err)
tb.Fatalf("Invalid version %s: %s", version, err)
}

return isPlatformVersionLessThan(tb, minv, platformVersion(tb))
Expand Down
4 changes: 2 additions & 2 deletions internal/testutils/feature_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import (

func platformVersion(tb testing.TB) internal.Version {
tb.Helper()
versionStr, ok := os.LookupEnv("CI_MAX_EFW_VERSION")
qt.Assert(tb, qt.IsTrue(ok), qt.Commentf("Missing CI_MAX_EFW_VERSION environment variable"))
versionStr, ok := os.LookupEnv("CI_EFW_VERSION")
qt.Assert(tb, qt.IsTrue(ok), qt.Commentf("Missing CI_EFW_VERSION environment variable"))
version, err := internal.NewVersion(versionStr)
qt.Assert(tb, qt.IsNil(err), qt.Commentf("Parse eBPF for Windows version"))
return version
Expand Down
4 changes: 2 additions & 2 deletions map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,7 @@ func TestNewMapInMapFromFD(t *testing.T) {
nested := createMapInMap(t, ArrayOfMaps, Array)

// Do not copy this, use Clone instead.
another, err := NewMapFromFD(dupFD(t, nested.FD()))
another, err := NewMapFromFD(testutils.DupFD(t, nested.FD()))
if err != nil {
t.Fatal("Can't create a new nested map from an FD")
}
Expand Down Expand Up @@ -1388,7 +1388,7 @@ func TestMapFromFD(t *testing.T) {

// If you're thinking about copying this, don't. Use
// Clone() instead.
m2, err := NewMapFromFD(dupFD(t, m.FD()))
m2, err := NewMapFromFD(testutils.DupFD(t, m.FD()))
testutils.SkipIfNotSupported(t, err)
if err != nil {
t.Fatal(err)
Expand Down
Loading