github.com/cilium/ebpf@v0.15.0/internal/testutils/feature.go (about)

     1  package testutils
     2  
     3  import (
     4  	"errors"
     5  	"os"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/cilium/ebpf/internal"
    10  )
    11  
    12  const (
    13  	ignoreKernelVersionEnvVar = "EBPF_TEST_IGNORE_KERNEL_VERSION"
    14  )
    15  
    16  func CheckFeatureTest(t *testing.T, fn func() error) {
    17  	checkFeatureTestError(t, fn())
    18  }
    19  
    20  func checkFeatureTestError(t *testing.T, err error) {
    21  	if err == nil {
    22  		return
    23  	}
    24  
    25  	var ufe *internal.UnsupportedFeatureError
    26  	if errors.As(err, &ufe) {
    27  		if ignoreKernelVersionCheck(t.Name()) {
    28  			t.Skipf("Ignoring error due to %s: %s", ignoreKernelVersionEnvVar, ufe.Error())
    29  		} else {
    30  			checkKernelVersion(t, ufe)
    31  		}
    32  	} else {
    33  		t.Error("Feature test failed:", err)
    34  	}
    35  }
    36  
    37  func CheckFeatureMatrix[K comparable](t *testing.T, fm internal.FeatureMatrix[K]) {
    38  	t.Helper()
    39  
    40  	for key, ft := range fm {
    41  		t.Run(ft.Name, func(t *testing.T) {
    42  			checkFeatureTestError(t, fm.Result(key))
    43  		})
    44  	}
    45  }
    46  
    47  func SkipIfNotSupported(tb testing.TB, err error) {
    48  	tb.Helper()
    49  
    50  	if err == internal.ErrNotSupported {
    51  		tb.Fatal("Unwrapped ErrNotSupported")
    52  	}
    53  
    54  	var ufe *internal.UnsupportedFeatureError
    55  	if errors.As(err, &ufe) {
    56  		checkKernelVersion(tb, ufe)
    57  		tb.Skip(ufe.Error())
    58  	}
    59  	if errors.Is(err, internal.ErrNotSupported) {
    60  		tb.Skip(err.Error())
    61  	}
    62  }
    63  
    64  func checkKernelVersion(tb testing.TB, ufe *internal.UnsupportedFeatureError) {
    65  	if ufe.MinimumVersion.Unspecified() {
    66  		return
    67  	}
    68  
    69  	if !isKernelLessThan(tb, ufe.MinimumVersion) {
    70  		tb.Helper()
    71  		tb.Fatalf("Feature '%s' isn't supported even though kernel is newer than %s",
    72  			ufe.Name, ufe.MinimumVersion)
    73  	}
    74  }
    75  
    76  func SkipOnOldKernel(tb testing.TB, minVersion, feature string) {
    77  	tb.Helper()
    78  
    79  	if IsKernelLessThan(tb, minVersion) {
    80  		tb.Skipf("Test requires at least kernel %s (due to missing %s)", minVersion, feature)
    81  	}
    82  }
    83  
    84  func IsKernelLessThan(tb testing.TB, minVersion string) bool {
    85  	tb.Helper()
    86  
    87  	minv, err := internal.NewVersion(minVersion)
    88  	if err != nil {
    89  		tb.Fatalf("Invalid version %s: %s", minVersion, err)
    90  	}
    91  
    92  	return isKernelLessThan(tb, minv)
    93  }
    94  
    95  func isKernelLessThan(tb testing.TB, minv internal.Version) bool {
    96  	tb.Helper()
    97  
    98  	if max := os.Getenv("CI_MAX_KERNEL_VERSION"); max != "" {
    99  		maxv, err := internal.NewVersion(max)
   100  		if err != nil {
   101  			tb.Fatalf("Invalid version %q in CI_MAX_KERNEL_VERSION: %s", max, err)
   102  		}
   103  
   104  		if maxv.Less(minv) {
   105  			tb.Fatalf("Test for %s will never execute on CI since %s is the most recent kernel", minv, maxv)
   106  		}
   107  	}
   108  
   109  	return kernelVersion(tb).Less(minv)
   110  }
   111  
   112  func kernelVersion(tb testing.TB) internal.Version {
   113  	tb.Helper()
   114  
   115  	v, err := internal.KernelVersion()
   116  	if err != nil {
   117  		tb.Fatal(err)
   118  	}
   119  	return v
   120  }
   121  
   122  // ignoreKernelVersionCheck checks if test name should be ignored for kernel version check by checking against environment var EBPF_TEST_IGNORE_KERNEL_VERSION.
   123  // EBPF_TEST_IGNORE_KERNEL_VERSION is a comma (,) separated list of test names for which kernel version check should be ignored.
   124  //
   125  // eg: EBPF_TEST_IGNORE_KERNEL_VERSION=TestABC,TestXYZ
   126  func ignoreKernelVersionCheck(tName string) bool {
   127  	tNames := os.Getenv(ignoreKernelVersionEnvVar)
   128  	if tNames == "" {
   129  		return false
   130  	}
   131  
   132  	ignored := strings.Split(tNames, ",")
   133  	for _, n := range ignored {
   134  		if strings.TrimSpace(n) == tName {
   135  			return true
   136  		}
   137  	}
   138  	return false
   139  }