diff --git a/test/integration/app_test.go b/test/integration/app_test.go new file mode 100644 index 000000000..587f4ee63 --- /dev/null +++ b/test/integration/app_test.go @@ -0,0 +1,83 @@ +//go:build integration_tests +// +build integration_tests + +package integration + +import ( + "bytes" + "context" + "io" + "testing" + "time" + + "github.com/kong/kubernetes-testing-framework/pkg/clusters" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + appGoCounterKustomize = "https://github.com/bpfman/bpfman/examples/config/default/go-app-counter/?timeout=120&ref=main" + appGoCounterUserspaceNs = "go-application-counter" + appGoCounterUserspaceDsName = "go-application-counter-ds" +) + +func TestApplicationGoCounter(t *testing.T) { + t.Log("deploying target required for uprobe counter program if its not already deployed") + require.NoError(t, clusters.KustomizeDeployForCluster(ctx, env.Cluster(), targetKustomize)) + + t.Log("waiting for go target userspace daemon to be available") + require.Eventually(t, func() bool { + daemon, err := env.Cluster().Client().AppsV1().DaemonSets(targetUserspaceNs).Get(ctx, targetUserspaceDsName, metav1.GetOptions{}) + require.NoError(t, err) + return daemon.Status.DesiredNumberScheduled == daemon.Status.NumberAvailable + }, + // Wait 5 minutes since cosign is slow, https://github.com/bpfman/bpfman/issues/1043 + 5*time.Minute, 10*time.Second) + + t.Log("deploying application counter program") + require.NoError(t, clusters.KustomizeDeployForCluster(ctx, env.Cluster(), appGoCounterKustomize)) + addCleanup(func(context.Context) error { + cleanupLog("cleaning up application counter program") + return clusters.KustomizeDeleteForCluster(ctx, env.Cluster(), appGoCounterKustomize) + }) + + t.Log("waiting for go application counter userspace daemon to be available") + require.Eventually(t, func() bool { + daemon, err := env.Cluster().Client().AppsV1().DaemonSets(appGoCounterUserspaceNs).Get(ctx, appGoCounterUserspaceDsName, metav1.GetOptions{}) + require.NoError(t, err) + return daemon.Status.DesiredNumberScheduled == daemon.Status.NumberAvailable + }, + // Wait 5 minutes since cosign is slow, https://github.com/bpfman/bpfman/issues/1043 + 5*time.Minute, 10*time.Second) + + pods, err := env.Cluster().Client().CoreV1().Pods(appGoCounterUserspaceNs).List(ctx, metav1.ListOptions{LabelSelector: "name=go-application-counter"}) + require.NoError(t, err) + goAppCounterPod := pods.Items[0] + + checkFunctions := []func(t *testing.T, output *bytes.Buffer) bool{ + doAppKprobeCheck, + doAppTcCheck, + doAppTracepointCheck, + doAppUprobeCheck, + doAppXdpCheck, + } + + for idx, f := range checkFunctions { + req := env.Cluster().Client().CoreV1().Pods(appGoCounterUserspaceNs).GetLogs(goAppCounterPod.Name, &corev1.PodLogOptions{}) + require.Eventually(t, func() bool { + logs, err := req.Stream(ctx) + require.NoError(t, err) + defer logs.Close() + output := new(bytes.Buffer) + _, err = io.Copy(output, logs) + require.NoError(t, err) + + if f(t, output) { + return true + } + t.Logf("check %d failed retrying, output %s", idx, output.String()) + return false + }, 30*time.Second, time.Second) + } +} diff --git a/test/integration/common.go b/test/integration/common.go new file mode 100644 index 000000000..3ffe4a086 --- /dev/null +++ b/test/integration/common.go @@ -0,0 +1,113 @@ +//go:build integration_tests +// +build integration_tests + +package integration + +import ( + "bytes" + "regexp" + "strconv" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func doKprobeCheck(t *testing.T, output *bytes.Buffer) bool { + str := `Kprobe count: ([0-9]+)` + if ok, count := doProbeCommonCheck(t, output, str); ok { + t.Logf("counted %d kprobe executions so far, BPF program is functioning", count) + return true + } + return false +} + +func doAppKprobeCheck(t *testing.T, output *bytes.Buffer) bool { + str := `Kprobe: count: ([0-9]+)` + if ok, count := doProbeCommonCheck(t, output, str); ok { + t.Logf("counted %d kprobe executions so far, BPF program is functioning", count) + return true + } + return false +} + +func doTcCheck(t *testing.T, output *bytes.Buffer) bool { + if strings.Contains(output.String(), "packets received") && strings.Contains(output.String(), "bytes received") { + t.Log("TC BPF program is functioning") + return true + } + return false +} + +func doAppTcCheck(t *testing.T, output *bytes.Buffer) bool { + if strings.Contains(output.String(), "TC:") && strings.Contains(output.String(), "packets received") && strings.Contains(output.String(), "bytes received") { + t.Log("TC BPF program is functioning") + return true + } + return false +} + +func doTracepointCheck(t *testing.T, output *bytes.Buffer) bool { + str := `SIGUSR1 signal count: ([0-9]+)` + if ok, count := doProbeCommonCheck(t, output, str); ok { + t.Logf("counted %d SIGUSR1 signals so far, BPF program is functioning", count) + return true + } + return false +} + +func doAppTracepointCheck(t *testing.T, output *bytes.Buffer) bool { + str := `Tracepoint: SIGUSR1 signal count: ([0-9]+)` + if ok, count := doProbeCommonCheck(t, output, str); ok { + t.Logf("counted %d SIGUSR1 signals so far, BPF program is functioning", count) + return true + } + return false +} + +func doUprobeCheck(t *testing.T, output *bytes.Buffer) bool { + str := `Uprobe count: ([0-9]+)` + if ok, count := doProbeCommonCheck(t, output, str); ok { + t.Logf("counted %d uprobe executions so far, BPF program is functioning", count) + return true + } + return false +} + +func doAppUprobeCheck(t *testing.T, output *bytes.Buffer) bool { + str := `Uprobe: count: ([0-9]+)` + if ok, count := doProbeCommonCheck(t, output, str); ok { + t.Logf("counted %d uprobe executions so far, BPF program is functioning", count) + return true + } + return false +} + +func doXdpCheck(t *testing.T, output *bytes.Buffer) bool { + if strings.Contains(output.String(), "packets received") && strings.Contains(output.String(), "bytes received") { + t.Log("XDP BPF program is functioning") + return true + } + return false +} + +func doAppXdpCheck(t *testing.T, output *bytes.Buffer) bool { + if strings.Contains(output.String(), "XDP:") && strings.Contains(output.String(), "packets received") && strings.Contains(output.String(), "bytes received") { + t.Log("XDP BPF program is functioning") + return true + } + return false +} + +func doProbeCommonCheck(t *testing.T, output *bytes.Buffer, str string) (bool, int) { + want := regexp.MustCompile(str) + matches := want.FindAllStringSubmatch(output.String(), -1) + if len(matches) >= 1 && len(matches[0]) >= 2 { + count, err := strconv.Atoi(matches[0][1]) + require.NoError(t, err) + if count > 0 { + return true, count + } + } + return false, 0 +} diff --git a/test/integration/kprobe_test.go b/test/integration/kprobe_test.go index 9c9e89709..fed93e2de 100644 --- a/test/integration/kprobe_test.go +++ b/test/integration/kprobe_test.go @@ -7,8 +7,6 @@ import ( "bytes" "context" "io" - "regexp" - "strconv" "testing" "time" @@ -45,7 +43,6 @@ func TestKprobeGoCounter(t *testing.T) { require.NoError(t, err) goKprobeCounterPod := pods.Items[0] - want := regexp.MustCompile(`Kprobe count: ([0-9]+)`) req := env.Cluster().Client().CoreV1().Pods(kprobeGoCounterUserspaceNs).GetLogs(goKprobeCounterPod.Name, &corev1.PodLogOptions{}) require.Eventually(t, func() bool { logs, err := req.Stream(ctx) @@ -56,15 +53,6 @@ func TestKprobeGoCounter(t *testing.T) { require.NoError(t, err) t.Logf("counter pod log %s", output.String()) - matches := want.FindAllStringSubmatch(output.String(), -1) - if len(matches) >= 1 && len(matches[0]) >= 2 { - count, err := strconv.Atoi(matches[0][1]) - require.NoError(t, err) - if count > 0 { - t.Logf("counted %d kprobe executions so far, BPF program is functioning", count) - return true - } - } - return false + return doKprobeCheck(t, output) }, 30*time.Second, time.Second) } diff --git a/test/integration/tc_test.go b/test/integration/tc_test.go index ca6469fb4..f3053f25d 100644 --- a/test/integration/tc_test.go +++ b/test/integration/tc_test.go @@ -7,7 +7,6 @@ import ( "bytes" "context" "io" - "strings" "testing" "time" @@ -54,9 +53,7 @@ func TestTcGoCounter(t *testing.T) { _, err = io.Copy(output, logs) require.NoError(t, err) t.Logf("counter pod log %s", output.String()) - if strings.Contains(output.String(), "packets received") && strings.Contains(output.String(), "bytes received") { - return true - } - return false + + return doTcCheck(t, output) }, 30*time.Second, time.Second) } diff --git a/test/integration/tracepoint_test.go b/test/integration/tracepoint_test.go index 15619f38c..e5a606111 100644 --- a/test/integration/tracepoint_test.go +++ b/test/integration/tracepoint_test.go @@ -7,8 +7,6 @@ import ( "bytes" "context" "io" - "regexp" - "strconv" "testing" "time" @@ -45,7 +43,6 @@ func TestTracepointGoCounter(t *testing.T) { require.NoError(t, err) goTracepointCounterPod := pods.Items[0] - want := regexp.MustCompile(`SIGUSR1 signal count: ([0-9]+)`) req := env.Cluster().Client().CoreV1().Pods(tracepointGoCounterUserspaceNs).GetLogs(goTracepointCounterPod.Name, &corev1.PodLogOptions{}) require.Eventually(t, func() bool { logs, err := req.Stream(ctx) @@ -55,16 +52,6 @@ func TestTracepointGoCounter(t *testing.T) { _, err = io.Copy(output, logs) require.NoError(t, err) t.Logf("counter pod log %s", output.String()) - - matches := want.FindAllStringSubmatch(output.String(), -1) - if len(matches) >= 1 && len(matches[0]) >= 2 { - count, err := strconv.Atoi(matches[0][1]) - require.NoError(t, err) - if count > 0 { - t.Logf("counted %d SIGUSR1 signals so far, BPF program is functioning", count) - return true - } - } - return false + return doTracepointCheck(t, output) }, 30*time.Second, time.Second) } diff --git a/test/integration/uprobe_test.go b/test/integration/uprobe_test.go index 8b19ab899..8208e2ae0 100644 --- a/test/integration/uprobe_test.go +++ b/test/integration/uprobe_test.go @@ -7,8 +7,6 @@ import ( "bytes" "context" "io" - "regexp" - "strconv" "testing" "time" @@ -64,7 +62,6 @@ func TestUprobeGoCounter(t *testing.T) { require.NoError(t, err) goUprobeCounterPod := pods.Items[0] - want := regexp.MustCompile(`Uprobe count: ([0-9]+)`) req := env.Cluster().Client().CoreV1().Pods(uprobeGoCounterUserspaceNs).GetLogs(goUprobeCounterPod.Name, &corev1.PodLogOptions{}) require.Eventually(t, func() bool { logs, err := req.Stream(ctx) @@ -74,16 +71,6 @@ func TestUprobeGoCounter(t *testing.T) { _, err = io.Copy(output, logs) require.NoError(t, err) t.Logf("counter pod log %s", output.String()) - - matches := want.FindAllStringSubmatch(output.String(), -1) - if len(matches) >= 1 && len(matches[0]) >= 2 { - count, err := strconv.Atoi(matches[0][1]) - require.NoError(t, err) - if count > 0 { - t.Logf("counted %d uprobe executions so far, BPF program is functioning", count) - return true - } - } - return false + return doUprobeCheck(t, output) }, 30*time.Second, time.Second) } diff --git a/test/integration/xdp_test.go b/test/integration/xdp_test.go index 9473c7f3e..5efb6a2d5 100644 --- a/test/integration/xdp_test.go +++ b/test/integration/xdp_test.go @@ -9,7 +9,6 @@ import ( "encoding/base64" "io" "os" - "strings" "testing" "time" @@ -136,9 +135,7 @@ func TestXdpGoCounter(t *testing.T) { _, err = io.Copy(output, logs) require.NoError(t, err) t.Logf("counter pod log %s", output.String()) - if strings.Contains(output.String(), "packets received") && strings.Contains(output.String(), "bytes received") { - return true - } - return false + + return doXdpCheck(t, output) }, 30*time.Second, time.Second) }