testing

package
v0.20.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 18, 2025 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package testing provides utilities for testing OpenTelemetry instrumentation in GoBricks applications.

This package offers in-memory exporters and helpers for asserting spans and metrics in unit tests without requiring external collectors or backends.

Usage:

// Create test trace provider
tp := NewTestTraceProvider()
defer tp.Shutdown(context.Background())

// Run your code that creates spans
tracer := tp.TestTracer()
_, span := tracer.Start(context.Background(), "test-span")
span.End()

// Assert spans
spans := tp.Exporter.GetSpans()
require.Len(t, spans, 1)
AssertSpanName(t, spans[0], "test-span")

Index

Examples

Constants

View Source
const (

	// TestTracerName is the default tracer name used in observability tests.
	// This eliminates duplication of "test" string literal across 17+ test files.
	TestTracerName = "test"
)

Variables

This section is empty.

Functions

func AssertMetricCount

func AssertMetricCount(t *testing.T, rm metricdata.ResourceMetrics, expected int)

AssertMetricCount asserts the total number of metrics collected.

func AssertMetricDescription

func AssertMetricDescription(t *testing.T, rm metricdata.ResourceMetrics, metricName, expectedDesc string)

AssertMetricDescription asserts the description of a metric.

func AssertMetricExists

func AssertMetricExists(t *testing.T, rm metricdata.ResourceMetrics, metricName string)

AssertMetricExists asserts that a metric with the given name exists.

func AssertMetricValue

func AssertMetricValue(t *testing.T, rm metricdata.ResourceMetrics, metricName string, expectedValue any)

AssertMetricValue finds a metric by name and asserts its value. For Sum metrics (counters, up-down counters), it asserts the first data point value. For Histogram metrics, it asserts the count.

func AssertSpanAttribute

func AssertSpanAttribute(t *testing.T, span *tracetest.SpanStub, key string, expected any)

AssertSpanAttribute asserts that a span has a specific attribute with the expected value.

func AssertSpanError

func AssertSpanError(t *testing.T, span *tracetest.SpanStub, expectedDesc string)

AssertSpanError asserts that a span has an error status with the expected description.

func AssertSpanName

func AssertSpanName(t *testing.T, span *tracetest.SpanStub, expected string)

AssertSpanName asserts the name of a span.

func AssertSpanStatus

func AssertSpanStatus(t *testing.T, span *tracetest.SpanStub, expectedCode codes.Code)

AssertSpanStatus asserts the status of a span.

func AssertSpanStatusDescription

func AssertSpanStatusDescription(t *testing.T, span *tracetest.SpanStub, expectedDesc string)

AssertSpanStatusDescription asserts the status description of a span.

func FindMetric

func FindMetric(rm metricdata.ResourceMetrics, metricName string) *metricdata.Metrics

FindMetric finds a metric by name in the ResourceMetrics. Returns nil if not found.

func GetMetricHistogramCount

func GetMetricHistogramCount(rm metricdata.ResourceMetrics, metricName string) (uint64, error)

GetMetricHistogramCount gets the count for a Histogram metric. Returns error if metric not found or wrong type.

func GetMetricSumValue

func GetMetricSumValue(rm metricdata.ResourceMetrics, metricName string) (any, error)

GetMetricSumValue gets the sum value for a Sum[int64] or Sum[float64] metric. Returns error if metric not found or wrong type.

Types

type SpanCollector

type SpanCollector struct {
	// contains filtered or unexported fields
}

SpanCollector provides a fluent API for filtering and asserting on captured spans.

Example

ExampleSpanCollector demonstrates filtering spans by name and attributes. Note: In actual tests, use NewSpanCollector with a testing.T parameter for assertions.

package main

import (
	"context"
	"fmt"

	"go.opentelemetry.io/otel/attribute"

	obtest "github.com/gaborage/go-bricks/observability/testing"
)

const (
	httpMethodAttr = "http.method"
	dbSystemAttr   = "db.system"

	databaseQuerySpan = "database-query"
)

func main() {
	tp := obtest.NewTestTraceProvider()
	defer tp.Shutdown(context.Background())

	tracer := tp.Tracer("example")

	// Create multiple spans with different attributes
	_, span1 := tracer.Start(context.Background(), databaseQuerySpan)
	span1.SetAttributes(attribute.String(dbSystemAttr, "postgresql"))
	span1.End()

	_, span2 := tracer.Start(context.Background(), "http-request")
	span2.SetAttributes(attribute.String(httpMethodAttr, "POST"))
	span2.End()

	_, span3 := tracer.Start(context.Background(), databaseQuerySpan)
	span3.SetAttributes(attribute.String(dbSystemAttr, "mongodb"))
	span3.End()

	// Get spans and count them by filtering
	spans := tp.Exporter.GetSpans()

	// Count database query spans
	dbCount := 0
	pgCount := 0
	for i := range spans {
		if spans[i].Name == databaseQuerySpan {
			dbCount++
			// Check for PostgreSQL attribute
			for _, attr := range spans[i].Attributes {
				if attr.Key == attribute.Key(dbSystemAttr) && attr.Value.AsString() == "postgresql" {
					pgCount++
					break
				}
			}
		}
	}

	fmt.Printf("Database queries: %d\n", dbCount)
	fmt.Printf("PostgreSQL queries: %d\n", pgCount)

}
Output:

Database queries: 2
PostgreSQL queries: 1

func NewSpanCollector

func NewSpanCollector(t *testing.T, exporter *tracetest.InMemoryExporter) *SpanCollector

NewSpanCollector creates a span collector from an in-memory exporter.

func (*SpanCollector) AssertCount

func (sc *SpanCollector) AssertCount(expected int) *SpanCollector

AssertCount asserts the number of collected spans.

func (*SpanCollector) AssertEmpty

func (sc *SpanCollector) AssertEmpty() *SpanCollector

AssertEmpty asserts that the collection is empty.

func (*SpanCollector) First

func (sc *SpanCollector) First() tracetest.SpanStub

First returns the first span in the collection. Fails the test if the collection is empty.

func (*SpanCollector) Get

func (sc *SpanCollector) Get(index int) tracetest.SpanStub

Get returns the span at the given index. Fails the test if the index is out of bounds.

func (*SpanCollector) Len

func (sc *SpanCollector) Len() int

Len returns the number of collected spans.

func (*SpanCollector) WithAttribute

func (sc *SpanCollector) WithAttribute(key string, value any) *SpanCollector

WithAttribute filters spans by attribute key-value pair and returns a new collector.

func (*SpanCollector) WithName

func (sc *SpanCollector) WithName(name string) *SpanCollector

WithName filters spans by name and returns a new collector.

type TestMeterProvider

type TestMeterProvider struct {
	*sdkmetric.MeterProvider
	Reader *sdkmetric.ManualReader
}

TestMeterProvider wraps the SDK MeterProvider and manual reader for testing.

func NewTestMeterProvider

func NewTestMeterProvider() *TestMeterProvider

NewTestMeterProvider creates a MeterProvider with a manual reader for testing. The manual reader allows collecting metrics on-demand for assertions without periodic exports.

Example:

mp := NewTestMeterProvider()
defer mp.Shutdown(context.Background())

// Use the provider in your tests
otel.SetMeterProvider(mp)
meter := mp.Meter("test")
counter, _ := meter.Int64Counter("test.counter")
counter.Add(context.Background(), 1)

// Collect metrics for assertions
rm := mp.Collect(t)
Example

ExampleNewTestMeterProvider demonstrates how to use the test meter provider to assert metrics created by your code.

package main

import (
	"context"
	"fmt"

	"go.opentelemetry.io/otel"

	obtest "github.com/gaborage/go-bricks/observability/testing"
)

func main() {
	// Create a test meter provider with manual reader
	mp := obtest.NewTestMeterProvider()
	defer mp.Shutdown(context.Background())

	// Set as global provider (or use directly)
	otel.SetMeterProvider(mp)

	// Your code that records metrics
	meter := mp.Meter("example-service")
	counter, _ := meter.Int64Counter("requests.count") // Metric options can be added here

	counter.Add(context.Background(), 1) // Attributes can be added to metric recordings

	counter.Add(context.Background(), 2)

	// Collect metrics for assertions
	// In real usage, you would pass the testing.T instance
	// rm := mp.Collect(t)
	fmt.Println("Metrics collected successfully")
}
Output:

Metrics collected successfully

func (*TestMeterProvider) Collect

Collect reads all metrics from the provider and returns them as ResourceMetrics. This is a convenience wrapper around Reader.Collect() with error handling.

type TestTraceProvider

type TestTraceProvider struct {
	*sdktrace.TracerProvider
	Exporter *tracetest.InMemoryExporter
}

TestTraceProvider wraps the SDK TracerProvider and in-memory exporter for testing.

func NewTestTraceProvider

func NewTestTraceProvider() *TestTraceProvider

NewTestTraceProvider creates a TracerProvider with an in-memory exporter for testing. The returned provider captures all spans in memory for assertion without sending them to an external backend.

Example:

tp := NewTestTraceProvider()
defer tp.Shutdown(context.Background())

// Use the provider in your tests
otel.SetTracerProvider(tp)

// Later, get spans for assertions
spans := tp.Exporter.GetSpans()
Example

ExampleNewTestTraceProvider demonstrates how to use the test trace provider to assert spans created by your code.

package main

import (
	"context"
	"fmt"

	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"

	obtest "github.com/gaborage/go-bricks/observability/testing"
)

const httpMethodAttr = "http.method"

func main() {
	// Create a test trace provider with in-memory exporter
	tp := obtest.NewTestTraceProvider()
	defer tp.Shutdown(context.Background())

	// Set as global provider (or use directly)
	otel.SetTracerProvider(tp)

	// Your code that creates spans
	tracer := tp.Tracer("example-service")
	_, span := tracer.Start(context.Background(), "process-request")
	span.SetAttributes(
		attribute.String(httpMethodAttr, "GET"),
		attribute.String("http.url", "/api/users"),
		attribute.Int("http.status_code", 200),
	)
	span.End()

	// Get captured spans for assertions
	spans := tp.Exporter.GetSpans()
	fmt.Printf("Captured %d spans\n", len(spans))
}
Output:

Captured 1 spans

func (*TestTraceProvider) TestTracer added in v0.18.0

func (ttp *TestTraceProvider) TestTracer() trace.Tracer

TestTracer returns a tracer with the standard test name. This is a convenience method that eliminates the need to pass TestTracerName to the Tracer() method in every test.

Example:

tp := NewTestTraceProvider()
tracer := tp.TestTracer()
_, span := tracer.Start(context.Background(), "operation")

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL