diff --git a/Makefile b/Makefile index b87768f0d..1a9ab000b 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ support/golbls_1_24.test: ./interpreter/golabels/test/main.go support/golbls_cgo.test: ./interpreter/golabels/test/main-cgo.go CGO_ENABLED=1 GOTOOLCHAIN=go1.24.1 go build -ldflags '-extldflags "-static"' -tags $(GO_TAGS),usecgo -o $@ $< -integration-test-binaries: generate ebpf rust-components support/golbls_1_23.test support/golbls_1_24.test support/golbls_cgo.test +integration-test-binaries: generate ebpf support/golbls_1_23.test support/golbls_1_24.test support/golbls_cgo.test $(foreach test_name, $(TEST_INTEGRATION_BINARY_DIRS), \ (go test -ldflags='-extldflags=-static' -trimpath -c \ -tags $(GO_TAGS),static_build,integration \ diff --git a/interpreter/golabels/test/main_test.go b/interpreter/golabels/test/main_test.go index 050cdd6f9..301349b81 100644 --- a/interpreter/golabels/test/main_test.go +++ b/interpreter/golabels/test/main_test.go @@ -4,25 +4,75 @@ package main import ( "context" + "math" "os" "os/exec" "strings" "testing" + "time" "github.com/stretchr/testify/require" - "go.opentelemetry.io/ebpf-profiler/testutils" + "go.opentelemetry.io/ebpf-profiler/host" + "go.opentelemetry.io/ebpf-profiler/libpf" + "go.opentelemetry.io/ebpf-profiler/reporter" + "go.opentelemetry.io/ebpf-profiler/tracer" tracertypes "go.opentelemetry.io/ebpf-profiler/tracer/types" ) +type mockIntervals struct{} + +func (mockIntervals) MonitorInterval() time.Duration { return 1 * time.Second } +func (mockIntervals) TracePollInterval() time.Duration { return 250 * time.Millisecond } +func (mockIntervals) PIDCleanupInterval() time.Duration { return 1 * time.Second } + +type mockReporter struct{} + +func (mockReporter) ExecutableKnown(_ libpf.FileID) bool { return true } +func (mockReporter) ExecutableMetadata(_ *reporter.ExecutableMetadataArgs) {} + +func isRoot() bool { + return os.Geteuid() == 0 +} + func TestGoLabels(t *testing.T) { - if !testutils.IsRoot() { + if !isRoot() { t.Skip("root privileges required") } + ctx := context.Background() - r := &testutils.MockReporter{} enabledTracers, _ := tracertypes.Parse("") enabledTracers.Enable(tracertypes.Labels) - traceCh, _ := testutils.StartTracer(context.Background(), t, enabledTracers, r) + + trc, err := tracer.NewTracer(ctx, &tracer.Config{ + Reporter: &mockReporter{}, + Intervals: &mockIntervals{}, + IncludeTracers: enabledTracers, + SamplesPerSecond: 20, + ProbabilisticInterval: 100, + ProbabilisticThreshold: 100, + OffCPUThreshold: uint32(math.MaxUint32 / 100), + DebugTracer: true, + }) + require.NoError(t, err) + + trc.StartPIDEventProcessor(ctx) + + err = trc.AttachTracer() + require.NoError(t, err) + + t.Log("Attached tracer program") + + err = trc.EnableProfiling() + require.NoError(t, err) + + err = trc.AttachSchedMonitor() + require.NoError(t, err) + + traceCh := make(chan *host.Trace) + + err = trc.StartMapMonitors(ctx, traceCh) + require.NoError(t, err) + for _, tc := range [][]string{ {"./golbls_1_23.test", "123"}, {"./golbls_1_24.test", "124"}, diff --git a/testutils/helpers.go b/testutils/helpers.go deleted file mode 100644 index dad5f2791..000000000 --- a/testutils/helpers.go +++ /dev/null @@ -1,127 +0,0 @@ -package testutils // import "go.opentelemetry.io/ebpf-profiler/testutils" - -import ( - "bufio" - "context" - "errors" - "io" - "math" - "os" - "strings" - "testing" - "time" - - log "github.com/sirupsen/logrus" - "github.com/stretchr/testify/require" - - "go.opentelemetry.io/ebpf-profiler/host" - "go.opentelemetry.io/ebpf-profiler/libpf" - "go.opentelemetry.io/ebpf-profiler/reporter" - "go.opentelemetry.io/ebpf-profiler/tracer" - tracertypes "go.opentelemetry.io/ebpf-profiler/tracer/types" -) - -type MockIntervals struct{} - -func (f MockIntervals) MonitorInterval() time.Duration { return 1 * time.Second } -func (f MockIntervals) TracePollInterval() time.Duration { return 250 * time.Millisecond } -func (f MockIntervals) PIDCleanupInterval() time.Duration { return 1 * time.Second } - -type MockReporter struct{} - -func (f MockReporter) ExecutableKnown(_ libpf.FileID) bool { - return true -} - -func (f MockReporter) ExecutableMetadata(_ *reporter.ExecutableMetadataArgs) { -} - -func StartTracer(ctx context.Context, t *testing.T, et tracertypes.IncludedTracers, - r reporter.SymbolReporter) (chan *host.Trace, *tracer.Tracer) { - trc, err := tracer.NewTracer(ctx, &tracer.Config{ - Reporter: r, - Intervals: &MockIntervals{}, - IncludeTracers: et, - SamplesPerSecond: 20, - ProbabilisticInterval: 100, - ProbabilisticThreshold: 100, - OffCPUThreshold: uint32(math.MaxUint32 / 100), - DebugTracer: true, - }) - require.NoError(t, err) - - go readTracePipe(ctx) - - trc.StartPIDEventProcessor(ctx) - - err = trc.AttachTracer() - require.NoError(t, err) - - log.Info("Attached tracer program") - - err = trc.EnableProfiling() - require.NoError(t, err) - - err = trc.AttachSchedMonitor() - require.NoError(t, err) - - traceCh := make(chan *host.Trace) - - // Spawn monitors for the various result maps - err = trc.StartMapMonitors(ctx, traceCh) - require.NoError(t, err) - - return traceCh, trc -} - -func getTracePipe() (*os.File, error) { - for _, mnt := range []string{ - "/sys/kernel/debug/tracing", - "/sys/kernel/tracing", - "/tracing", - "/trace"} { - t, err := os.Open(mnt + "/trace_pipe") - if err == nil { - return t, nil - } - log.Errorf("Could not open trace_pipe at %s: %s", mnt, err) - } - return nil, os.ErrNotExist -} - -func readTracePipe(ctx context.Context) { - tp, err := getTracePipe() - if err != nil { - log.Warning("Could not open trace_pipe, check that debugfs is mounted") - return - } - - // When we're done kick ReadString out of blocked I/O. - go func() { - <-ctx.Done() - _ = tp.Close() - }() - - r := bufio.NewReader(tp) - for { - line, err := r.ReadString('\n') - if err != nil { - if errors.Is(err, io.EOF) { - continue - } - if errors.Is(err, os.ErrClosed) { - return - } - log.Error(err) - return - } - line = strings.TrimSpace(line) - if line != "" { - log.Infof("%s", line) - } - } -} - -func IsRoot() bool { - return os.Geteuid() == 0 -} diff --git a/tracer/ebpf_integration_test.go b/tracer/ebpf_integration_test.go index ebfd46194..8fb8700f9 100644 --- a/tracer/ebpf_integration_test.go +++ b/tracer/ebpf_integration_test.go @@ -21,13 +21,24 @@ import ( "go.opentelemetry.io/ebpf-profiler/host" "go.opentelemetry.io/ebpf-profiler/libpf" + "go.opentelemetry.io/ebpf-profiler/reporter" "go.opentelemetry.io/ebpf-profiler/rlimit" "go.opentelemetry.io/ebpf-profiler/support" - "go.opentelemetry.io/ebpf-profiler/testutils" "go.opentelemetry.io/ebpf-profiler/tracer" tracertypes "go.opentelemetry.io/ebpf-profiler/tracer/types" ) +type mockIntervals struct{} + +func (mockIntervals) MonitorInterval() time.Duration { return 1 * time.Second } +func (mockIntervals) TracePollInterval() time.Duration { return 250 * time.Millisecond } +func (mockIntervals) PIDCleanupInterval() time.Duration { return 1 * time.Second } + +type mockReporter struct{} + +func (mockReporter) ExecutableKnown(_ libpf.FileID) bool { return true } +func (mockReporter) ExecutableMetadata(_ *reporter.ExecutableMetadataArgs) {} + // forceContextSwitch makes sure two Go threads are running concurrently // and that there will be a context switch between those two. func forceContextSwitch() { @@ -105,8 +116,8 @@ func TestTraceTransmissionAndParsing(t *testing.T) { enabledTracers, _ := tracertypes.Parse("") enabledTracers.Enable(tracertypes.PythonTracer) tr, err := tracer.NewTracer(ctx, &tracer.Config{ - Reporter: &testutils.MockReporter{}, - Intervals: &testutils.MockIntervals{}, + Reporter: &mockReporter{}, + Intervals: &mockIntervals{}, IncludeTracers: enabledTracers, FilterErrorFrames: false, SamplesPerSecond: 20, @@ -228,6 +239,15 @@ Loop: } func TestAllTracers(t *testing.T) { - _, _ = testutils.StartTracer(context.Background(), t, tracertypes.AllTracers(), - &testutils.MockReporter{}) + _, err := tracer.NewTracer(context.Background(), &tracer.Config{ + Reporter: &mockReporter{}, + Intervals: &mockIntervals{}, + IncludeTracers: tracertypes.AllTracers(), + SamplesPerSecond: 20, + ProbabilisticInterval: 100, + ProbabilisticThreshold: 100, + OffCPUThreshold: uint32(math.MaxUint32 / 100), + DebugTracer: true, + }) + require.NoError(t, err) } diff --git a/tracer/tracer.go b/tracer/tracer.go index cc585cc0e..e40594d25 100644 --- a/tracer/tracer.go +++ b/tracer/tracer.go @@ -40,7 +40,7 @@ import ( "go.opentelemetry.io/ebpf-profiler/tracer/types" ) -// Compile time check to make sure config.Times satisfies the interfaces. +// Compile time check to make sure times.Times satisfies the interfaces. var _ Intervals = (*times.Times)(nil) const ( diff --git a/tracer/tracer_test.go b/tracer/tracer_test.go index 83d057428..75e242ff0 100644 --- a/tracer/tracer_test.go +++ b/tracer/tracer_test.go @@ -1,10 +1,11 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -// Package tracer contains functionality for populating tracers. package tracer // import "go.opentelemetry.io/ebpf-profiler/tracer" -import cebpf "github.com/cilium/ebpf" +import ( + cebpf "github.com/cilium/ebpf" +) // Make accessible for testing func (t *Tracer) GetEbpfMaps() map[string]*cebpf.Map {