github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/cmd/bpf2go/compile_test.go (about)

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