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 }