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