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