Repository: cilium/ebpf
Pull request #161 (2020-11-13 12:12:04)

cmd/bpf2go: use temporary module for tests
Create a temporary module instead of using a temporary subdirectory to
test compilation. This avoids dirtying the repository and avoids
interacting with the 9pfs root mount in the test VM.


Patch:
diff --git a/cmd/bpf2go/output.go b/cmd/bpf2go/output.go
index e97a328..642793f 100644
--- a/cmd/bpf2go/output.go
+++ b/cmd/bpf2go/output.go
@@ -14,6 +14,8 @@ import (
 	"github.com/cilium/ebpf"
 )
 
+const ebpfModule = "github.com/cilium/ebpf"
+
 const commonRaw = `// Code generated by bpf2go; DO NOT EDIT.
 {{- range .Tags }}
 // +build {{ . }}
@@ -26,7 +28,7 @@ import (
 	"fmt"
 	"io"
 
-	"github.com/cilium/ebpf"
+	"{{ .Module }}"
 )
 
 type {{ .Name.Specs }} struct {
@@ -210,6 +212,7 @@ func writeCommon(args writeArgs) error {
 	}
 
 	ctx := struct {
+		Module   string
 		Package  string
 		Tags     []string
 		Name     templateName
@@ -218,6 +221,7 @@ func writeCommon(args writeArgs) error {
 		Programs map[string]*ebpf.ProgramSpec
 		Bytes    string
 	}{
+		ebpfModule,
 		args.pkg,
 		args.tags,
 		templateName(args.ident),


Test patch:
diff --git a/cmd/bpf2go/compile_test.go b/cmd/bpf2go/compile_test.go
index b70da70..0876fd8 100644
--- a/cmd/bpf2go/compile_test.go
+++ b/cmd/bpf2go/compile_test.go
@@ -13,8 +13,7 @@ import (
 const minimalSocketFilter = `__attribute__((section("socket"), used)) int main() { return 0; }`
 
 func TestCompile(t *testing.T) {
-	dir, cleanup := mustWriteTempFile(t, "test.c", minimalSocketFilter)
-	defer cleanup()
+	dir := mustWriteTempFile(t, "test.c", minimalSocketFilter)
 
 	var dep bytes.Buffer
 	err := compile(compileArgs{
@@ -47,8 +46,7 @@ func TestCompile(t *testing.T) {
 }
 
 func TestReproducibleCompile(t *testing.T) {
-	dir, cleanup := mustWriteTempFile(t, "test.c", minimalSocketFilter)
-	defer cleanup()
+	dir := mustWriteTempFile(t, "test.c", minimalSocketFilter)
 
 	err := compile(compileArgs{
 		cc:     "clang-9",
@@ -135,21 +133,19 @@ nothing:
 	}
 }
 
-func mustWriteTempFile(t *testing.T, name, contents string) (string, func()) {
+func mustWriteTempFile(t *testing.T, name, contents string) string {
 	t.Helper()
 
 	tmp, err := ioutil.TempDir("", "bpf2go")
 	if err != nil {
 		t.Fatal(err)
 	}
-
-	cleanup := func() { os.RemoveAll(tmp) }
+	t.Cleanup(func() { os.RemoveAll(tmp) })
 
 	tmpFile := filepath.Join(tmp, name)
 	if err := ioutil.WriteFile(tmpFile, []byte(contents), 0660); err != nil {
-		cleanup()
 		t.Fatal(err)
 	}
 
-	return tmp, cleanup
+	return tmp
 }
diff --git a/cmd/bpf2go/main_test.go b/cmd/bpf2go/main_test.go
index ea4d216..4f9b23c 100644
--- a/cmd/bpf2go/main_test.go
+++ b/cmd/bpf2go/main_test.go
@@ -2,6 +2,7 @@ package main
 
 import (
 	"bytes"
+	"fmt"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -10,22 +11,47 @@ import (
 )
 
 func TestRun(t *testing.T) {
-	dir, cleanup := mustWriteTempFile(t, "test.c", minimalSocketFilter)
-	defer cleanup()
+	dir := mustWriteTempFile(t, "test.c", minimalSocketFilter)
 
 	cwd, err := os.Getwd()
 	if err != nil {
 		t.Fatal(err)
 	}
 
-	// The temporary package has to be in the same module, otherwise
-	// we can't test against unreleased versions of the package.
-	tmpDir, err := ioutil.TempDir(cwd, "bpf2go-module-*")
+	modRoot := filepath.Clean(filepath.Join(cwd, "../.."))
+	if _, err := os.Stat(filepath.Join(modRoot, "go.mod")); os.IsNotExist(err) {
+		t.Fatal("No go.mod file in", modRoot)
+	}
+
+	tmpDir, err := ioutil.TempDir("", "bpf2go-module-*")
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer os.RemoveAll(tmpDir)
 
+	execInModule := func(name string, args ...string) {
+		t.Helper()
+
+		cmd := exec.Command(name, args...)
+		cmd.Dir = tmpDir
+		if out, err := cmd.CombinedOutput(); err != nil {
+			if out := string(out); out != "" {
+				t.Log(out)
+			}
+			t.Fatalf("Can't execute %s: %v", name, args)
+		}
+	}
+
+	execInModule("go", "mod", "init", "bpf2go-test")
+
+	execInModule("go", "mod", "edit",
+		// Require the module. The version doesn't matter due to the replace
+		// below.
+		fmt.Sprintf("-require=%s@v0.0.0", ebpfModule),
+		// Replace the module with the current version.
+		fmt.Sprintf("-replace=%s=%s", ebpfModule, modRoot),
+	)
+
 	err = run(ioutil.Discard, "foo", tmpDir, []string{
 		"-cc", "clang-9",
 		"bar",
@@ -40,18 +66,21 @@ func TestRun(t *testing.T) {
 		"amd64", // little-endian
 		"s390x", // big-endian
 	} {
-		goBin := exec.Command("go", "build", tmpDir)
-		goBin.Env = append(os.Environ(),
-			"GOOS=linux",
-			"GOARCH="+arch,
-		)
-		out, err := goBin.CombinedOutput()
-		if err != nil {
-			if out := string(out); out != "" {
-				t.Log(out)
+		t.Run(arch, func(t *testing.T) {
+			goBin := exec.Command("go", "build", "-mod=mod")
+			goBin.Dir = tmpDir
+			goBin.Env = append(os.Environ(),
+				"GOOS=linux",
+				"GOARCH="+arch,
+			)
+			out, err := goBin.CombinedOutput()
+			if err != nil {
+				if out := string(out); out != "" {
+					t.Log(out)
+				}
+				t.Error("Can't compile package:", err)
 			}
-			t.Errorf("Can't compile resulting package for arch %s: %s", arch, err)
-		}
+		})
 	}
 }
 
diff --git a/run-tests.sh b/run-tests.sh
index 0e85c63..bd349f9 100755
--- a/run-tests.sh
+++ b/run-tests.sh
@@ -12,7 +12,8 @@ if [[ "${1:-}" = "--in-vm" ]]; then
   export CGO_ENABLED=0
   export GOFLAGS=-mod=readonly
   export GOPATH=/run/go-path
-  export GOPROXY=file:///run/go-root/pkg/mod/cache/download
+  export GOPROXY=file:///run/go-path/pkg/mod/cache/download
+  export GOSUMDB=off
   export GOCACHE=/run/go-cache
 
   elfs=""