...

Source file src/github.com/cilium/ebpf/cmd/bpf2go/compile_test.go

Documentation: github.com/cilium/ebpf/cmd/bpf2go

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"os"
     6  	"path/filepath"
     7  	"reflect"
     8  	"strings"
     9  	"testing"
    10  )
    11  
    12  const minimalSocketFilter = `__attribute__((section("socket"), used)) int main() { return 0; }`
    13  
    14  // Test against the minimum supported version of clang to avoid regressions.
    15  const (
    16  	clangBin = "clang-9"
    17  )
    18  
    19  func TestCompile(t *testing.T) {
    20  	dir := mustWriteTempFile(t, "test.c", minimalSocketFilter)
    21  
    22  	var dep bytes.Buffer
    23  	err := compile(compileArgs{
    24  		cc:     clangBin,
    25  		dir:    dir,
    26  		source: filepath.Join(dir, "test.c"),
    27  		dest:   filepath.Join(dir, "test.o"),
    28  		dep:    &dep,
    29  	})
    30  	if err != nil {
    31  		t.Fatal("Can't compile:", err)
    32  	}
    33  
    34  	stat, err := os.Stat(filepath.Join(dir, "test.o"))
    35  	if err != nil {
    36  		t.Fatal("Can't stat output:", err)
    37  	}
    38  
    39  	if stat.Size() == 0 {
    40  		t.Error("Compilation creates an empty file")
    41  	}
    42  
    43  	if dep.Len() == 0 {
    44  		t.Error("Compilation doesn't generate depinfo")
    45  	}
    46  
    47  	if _, err := parseDependencies(dir, &dep); err != nil {
    48  		t.Error("Can't parse dependencies:", err)
    49  	}
    50  }
    51  
    52  func TestReproducibleCompile(t *testing.T) {
    53  	dir := mustWriteTempFile(t, "test.c", minimalSocketFilter)
    54  
    55  	err := compile(compileArgs{
    56  		cc:     clangBin,
    57  		dir:    dir,
    58  		source: filepath.Join(dir, "test.c"),
    59  		dest:   filepath.Join(dir, "a.o"),
    60  	})
    61  	if err != nil {
    62  		t.Fatal("Can't compile:", err)
    63  	}
    64  
    65  	err = compile(compileArgs{
    66  		cc:     clangBin,
    67  		dir:    dir,
    68  		source: filepath.Join(dir, "test.c"),
    69  		dest:   filepath.Join(dir, "b.o"),
    70  	})
    71  	if err != nil {
    72  		t.Fatal("Can't compile:", err)
    73  	}
    74  
    75  	aBytes, err := os.ReadFile(filepath.Join(dir, "a.o"))
    76  	if err != nil {
    77  		t.Fatal(err)
    78  	}
    79  
    80  	bBytes, err := os.ReadFile(filepath.Join(dir, "b.o"))
    81  	if err != nil {
    82  		t.Fatal(err)
    83  	}
    84  
    85  	if !bytes.Equal(aBytes, bBytes) {
    86  		t.Error("Compiling the same file twice doesn't give the same result")
    87  	}
    88  }
    89  
    90  func TestTriggerMissingTarget(t *testing.T) {
    91  	dir := mustWriteTempFile(t, "test.c", `_Pragma(__BPF_TARGET_MISSING);`)
    92  
    93  	err := compile(compileArgs{
    94  		cc:     clangBin,
    95  		dir:    dir,
    96  		source: filepath.Join(dir, "test.c"),
    97  		dest:   filepath.Join(dir, "a.o"),
    98  	})
    99  
   100  	if err == nil {
   101  		t.Fatal("No error when compiling __BPF_TARGET_MISSING")
   102  	}
   103  }
   104  
   105  func TestParseDependencies(t *testing.T) {
   106  	const input = `main.go: /foo/bar baz
   107  
   108  frob: /gobble \
   109   gubble
   110  
   111  nothing:
   112  `
   113  
   114  	have, err := parseDependencies("/foo", strings.NewReader(input))
   115  	if err != nil {
   116  		t.Fatal("Can't parse dependencies:", err)
   117  	}
   118  
   119  	want := []dependency{
   120  		{"/foo/main.go", []string{"/foo/bar", "/foo/baz"}},
   121  		{"/foo/frob", []string{"/gobble", "/foo/gubble"}},
   122  		{"/foo/nothing", nil},
   123  	}
   124  
   125  	if !reflect.DeepEqual(have, want) {
   126  		t.Logf("Have: %#v", have)
   127  		t.Logf("Want: %#v", want)
   128  		t.Error("Result doesn't match")
   129  	}
   130  
   131  	output, err := adjustDependencies("/foo", want)
   132  	if err != nil {
   133  		t.Error("Can't adjust dependencies")
   134  	}
   135  
   136  	const wantOutput = `main.go: \
   137   bar \
   138   baz
   139  
   140  frob: \
   141   ../gobble \
   142   gubble
   143  
   144  nothing:
   145  
   146  `
   147  
   148  	if have := string(output); have != wantOutput {
   149  		t.Logf("Have:\n%s", have)
   150  		t.Logf("Want:\n%s", wantOutput)
   151  		t.Error("Output doesn't match")
   152  	}
   153  }
   154  
   155  func mustWriteTempFile(t *testing.T, name, contents string) string {
   156  	t.Helper()
   157  
   158  	tmp, err := os.MkdirTemp("", "bpf2go")
   159  	if err != nil {
   160  		t.Fatal(err)
   161  	}
   162  	t.Cleanup(func() { os.RemoveAll(tmp) })
   163  
   164  	tmpFile := filepath.Join(tmp, name)
   165  	if err := os.WriteFile(tmpFile, []byte(contents), 0660); err != nil {
   166  		t.Fatal(err)
   167  	}
   168  
   169  	return tmp
   170  }
   171  

View as plain text