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 }