From e7790c44fe5e375511d848f1e8507284c909ff9a Mon Sep 17 00:00:00 2001 From: Hank Donnay Date: Mon, 23 Jun 2025 12:38:14 -0500 Subject: [PATCH] test: wip: main wrapper with trace helpers Signed-off-by: Hank Donnay --- go.mod | 3 + go.sum | 4 + test/main.go | 127 +++++++++++++++++++++ test/rhel/rhcc_matcher_integration_test.go | 6 +- 4 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 test/main.go diff --git a/go.mod b/go.mod index dacc59077..1203fea3d 100644 --- a/go.mod +++ b/go.mod @@ -40,6 +40,8 @@ require ( modernc.org/sqlite v1.37.1 ) +require go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0 // indirect + require ( github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -65,6 +67,7 @@ require ( github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/otel/metric v1.36.0 // indirect + go.opentelemetry.io/otel/sdk v1.36.0 golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect golang.org/x/mod v0.25.0 // indirect google.golang.org/protobuf v1.36.5 // indirect diff --git a/go.sum b/go.sum index 44ddc92fb..5083690c0 100644 --- a/go.sum +++ b/go.sum @@ -206,8 +206,12 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0 h1:G8Xec/SgZQricwWBJF/mHZc7A02YHedfFDENwJEdRA0= +go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.36.0/go.mod h1:PD57idA/AiFD5aqoxGxCvT/ILJPeHy3MjqU/NS7KogY= go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= +go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= +go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= diff --git a/test/main.go b/test/main.go new file mode 100644 index 000000000..86eded1ab --- /dev/null +++ b/test/main.go @@ -0,0 +1,127 @@ +package test + +import ( + "context" + "errors" + "flag" + "fmt" + "os" + "testing" + "time" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/exporters/stdout/stdouttrace" + "go.opentelemetry.io/otel/sdk/resource" + "go.opentelemetry.io/otel/sdk/trace" + + "github.com/quay/claircore/test/integration" +) + +// Main ... +// +// This function panics if any setup fails. +// +// func MainTest(m *testing.M){ +// test.Main(m) +// } +func Main(m *testing.M, options ...Option) { + var code int + var setup testSetup + defer func() { + if err := setup.Close(); err != nil { + fmt.Fprintf(os.Stderr, "error while cleaning up: %v\n", err) + code++ + } + if code != 0 { + os.Exit(code) + } + }() + + flag.Func("app-trace", "path to write for application traces (otel JSON format)", func(arg string) error { + options = append(options, WithApplicationTrace(arg)) + return nil + }) + flag.Parse() + + for _, f := range options { + if err := f(&setup); err != nil { + panic(err) + } + } + + if setup.AppTraceOut != nil { + // Initialize our stdout exporter, configured to write to a file. + exporter, err := stdouttrace.New(stdouttrace.WithWriter(setup.AppTraceOut)) + if err != nil { + panic(fmt.Errorf("creating stdout exporter: %w", err)) + } + r, err := resource.Merge( + resource.Default(), + resource.NewSchemaless(attribute.String("test.start", time.Now().Format(time.RFC3339)))) + if err != nil { + panic(fmt.Errorf("creating stdout exporter: %w", err)) + } + // Set the global trace provider configured with that exporter. + setup.AppTraceProvider = trace.NewTracerProvider( + trace.WithSampler(trace.AlwaysSample()), + trace.WithResource(r), + trace.WithBatcher(exporter), + ) + otel.SetTracerProvider(setup.AppTraceProvider) + + func() { + _, span := otel.Tracer("github.com/quay/claircore/test").Start(context.Background(), "Main") + span.AddEvent("start") + span.End() + }() + } + + code = m.Run() +} + +type testSetup struct { + AppTraceOut *os.File + AppTraceProvider *trace.TracerProvider + DBTeardown func() +} + +// Option is the type for configuring the [Main] funtion. +type Option func(*testSetup) error + +// DBSetup arranges for [integration.DBSetup] to be called before tests are run. +func DBSetup(s *testSetup) error { + s.DBTeardown = integration.DBSetup() + return nil +} + +// WithApplicationTrace arranges for OTel JSON formatted traces to "path". +func WithApplicationTrace(path string) Option { + return func(s *testSetup) error { + var prevErr, openErr error + if s.AppTraceOut != nil { + fmt.Fprintf(os.Stderr, "closing previously specified trace file: %q", s.AppTraceOut.Name()) + prevErr = s.AppTraceOut.Close() + s.AppTraceOut = nil + } + if path != "" { + s.AppTraceOut, openErr = os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o644) + } + return errors.Join(prevErr, openErr) + } +} + +// Close does teardown. +func (s *testSetup) Close() error { + var errs []error + if s.DBTeardown != nil { + s.DBTeardown() + } + if s.AppTraceOut != nil { + // Shut down the trace provider and flush everything. + timeout, done := context.WithTimeout(context.Background(), 10*time.Second) + errs = append(errs, s.AppTraceProvider.Shutdown(timeout), s.AppTraceOut.Close()) + done() + } + return errors.Join(errs...) +} diff --git a/test/rhel/rhcc_matcher_integration_test.go b/test/rhel/rhcc_matcher_integration_test.go index 9191a5cd9..d7e8fcd9f 100644 --- a/test/rhel/rhcc_matcher_integration_test.go +++ b/test/rhel/rhcc_matcher_integration_test.go @@ -19,15 +19,13 @@ import ( "github.com/quay/claircore/pkg/ctxlock/v2" "github.com/quay/claircore/rhel/rhcc" "github.com/quay/claircore/rhel/vex" + "github.com/quay/claircore/test" "github.com/quay/claircore/test/integration" testpostgres "github.com/quay/claircore/test/postgres" ) func TestMain(m *testing.M) { - var c int - defer func() { os.Exit(c) }() - defer integration.DBSetup()() - c = m.Run() + test.Main(m, test.DBSetup) } func TestMatcherIntegration(t *testing.T) {