From dc210e99a461a8cba62b721398bbde1f73afafb3 Mon Sep 17 00:00:00 2001 From: Joe Stephenson Date: Fri, 30 May 2025 08:00:23 +0100 Subject: [PATCH] sdk/trace: Remove internaltest package (#6846) Closes #6540 Closes #6535 --- internal/gen.go | 11 - internal/shared/internaltest/doc.go.tmpl | 8 - internal/shared/internaltest/env.go.tmpl | 90 ----- internal/shared/internaltest/env_test.go.tmpl | 226 ------------ internal/shared/internaltest/errors.go.tmpl | 19 - internal/shared/internaltest/harness.go.tmpl | 334 ------------------ .../internaltest/text_map_carrier.go.tmpl | 133 ------- .../text_map_carrier_test.go.tmpl | 73 ---- .../internaltest/text_map_propagator.go.tmpl | 104 ------ .../text_map_propagator_test.go.tmpl | 61 ---- sdk/internal/env/env_test.go | 7 - sdk/internal/gen.go | 10 - sdk/internal/internaltest/doc.go | 8 - sdk/internal/internaltest/env.go | 90 ----- sdk/internal/internaltest/env_test.go | 226 ------------ sdk/internal/internaltest/errors.go | 19 - sdk/internal/internaltest/harness.go | 334 ------------------ sdk/internal/internaltest/text_map_carrier.go | 133 ------- .../internaltest/text_map_carrier_test.go | 73 ---- .../internaltest/text_map_propagator.go | 104 ------ .../internaltest/text_map_propagator_test.go | 61 ---- 21 files changed, 2124 deletions(-) delete mode 100644 internal/gen.go delete mode 100644 internal/shared/internaltest/doc.go.tmpl delete mode 100644 internal/shared/internaltest/env.go.tmpl delete mode 100644 internal/shared/internaltest/env_test.go.tmpl delete mode 100644 internal/shared/internaltest/errors.go.tmpl delete mode 100644 internal/shared/internaltest/harness.go.tmpl delete mode 100644 internal/shared/internaltest/text_map_carrier.go.tmpl delete mode 100644 internal/shared/internaltest/text_map_carrier_test.go.tmpl delete mode 100644 internal/shared/internaltest/text_map_propagator.go.tmpl delete mode 100644 internal/shared/internaltest/text_map_propagator_test.go.tmpl delete mode 100644 sdk/internal/internaltest/doc.go delete mode 100644 sdk/internal/internaltest/env.go delete mode 100644 sdk/internal/internaltest/env_test.go delete mode 100644 sdk/internal/internaltest/errors.go delete mode 100644 sdk/internal/internaltest/harness.go delete mode 100644 sdk/internal/internaltest/text_map_carrier.go delete mode 100644 sdk/internal/internaltest/text_map_carrier_test.go delete mode 100644 sdk/internal/internaltest/text_map_propagator.go delete mode 100644 sdk/internal/internaltest/text_map_propagator_test.go diff --git a/internal/gen.go b/internal/gen.go deleted file mode 100644 index 516c7fe54..000000000 --- a/internal/gen.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -// Package internal contains utility functions and internal implementations -package internal // import "go.opentelemetry.io/otel/internal" - -//go:generate gotmpl --body=./shared/internaltest/doc.go.tmpl "--data={}" --out=internaltest/doc.go -//go:generate gotmpl --body=./shared/internaltest/text_map_carrier.go.tmpl "--data={}" --out=internaltest/text_map_carrier.go -//go:generate gotmpl --body=./shared/internaltest/text_map_carrier_test.go.tmpl "--data={}" --out=internaltest/text_map_carrier_test.go -//go:generate gotmpl --body=./shared/internaltest/text_map_propagator.go.tmpl "--data={}" --out=internaltest/text_map_propagator.go -//go:generate gotmpl --body=./shared/internaltest/text_map_propagator_test.go.tmpl "--data={}" --out=internaltest/text_map_propagator_test.go diff --git a/internal/shared/internaltest/doc.go.tmpl b/internal/shared/internaltest/doc.go.tmpl deleted file mode 100644 index 8d205e891..000000000 --- a/internal/shared/internaltest/doc.go.tmpl +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/doc.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -// Package internaltest provides testing functionality. -package internaltest diff --git a/internal/shared/internaltest/env.go.tmpl b/internal/shared/internaltest/env.go.tmpl deleted file mode 100644 index e45af7737..000000000 --- a/internal/shared/internaltest/env.go.tmpl +++ /dev/null @@ -1,90 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/env.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package internaltest - -import ( - "os" -) - -type Env struct { - Name string - Value string - Exists bool -} - -// EnvStore stores and recovers environment variables. -type EnvStore interface { - // Records the environment variable into the store. - Record(key string) - - // Restore recovers the environment variables in the store. - Restore() error -} - -var _ EnvStore = (*envStore)(nil) - -type envStore struct { - store map[string]Env -} - -func (s *envStore) add(env Env) { - s.store[env.Name] = env -} - -func (s *envStore) Restore() error { - var err error - for _, v := range s.store { - if v.Exists { - err = os.Setenv(v.Name, v.Value) - } else { - err = os.Unsetenv(v.Name) - } - if err != nil { - return err - } - } - return nil -} - -func (s *envStore) setEnv(key, value string) error { - s.Record(key) - - err := os.Setenv(key, value) - if err != nil { - return err - } - return nil -} - -func (s *envStore) Record(key string) { - originValue, exists := os.LookupEnv(key) - s.add(Env{ - Name: key, - Value: originValue, - Exists: exists, - }) -} - -func NewEnvStore() EnvStore { - return newEnvStore() -} - -func newEnvStore() *envStore { - return &envStore{store: make(map[string]Env)} -} - -func SetEnvVariables(env map[string]string) (EnvStore, error) { - envStore := newEnvStore() - - for k, v := range env { - err := envStore.setEnv(k, v) - if err != nil { - return nil, err - } - } - return envStore, nil -} diff --git a/internal/shared/internaltest/env_test.go.tmpl b/internal/shared/internaltest/env_test.go.tmpl deleted file mode 100644 index 093d06812..000000000 --- a/internal/shared/internaltest/env_test.go.tmpl +++ /dev/null @@ -1,226 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/env_test.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package internaltest - -import ( - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" -) - -type EnvStoreTestSuite struct { - suite.Suite -} - -func (s *EnvStoreTestSuite) Test_add() { - envStore := newEnvStore() - - e := Env{ - Name: "name", - Value: "value", - Exists: true, - } - envStore.add(e) - envStore.add(e) - - s.Len(envStore.store, 1) -} - -func (s *EnvStoreTestSuite) TestRecord() { - testCases := []struct { - name string - env Env - expectedEnvStore *envStore - }{ - { - name: "record exists env", - env: Env{ - Name: "name", - Value: "value", - Exists: true, - }, - expectedEnvStore: &envStore{store: map[string]Env{ - "name": { - Name: "name", - Value: "value", - Exists: true, - }, - }}, - }, - { - name: "record exists env, but its value is empty", - env: Env{ - Name: "name", - Value: "", - Exists: true, - }, - expectedEnvStore: &envStore{store: map[string]Env{ - "name": { - Name: "name", - Value: "", - Exists: true, - }, - }}, - }, - { - name: "record not exists env", - env: Env{ - Name: "name", - Exists: false, - }, - expectedEnvStore: &envStore{store: map[string]Env{ - "name": { - Name: "name", - Exists: false, - }, - }}, - }, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - if tc.env.Exists { - s.NoError(os.Setenv(tc.env.Name, tc.env.Value)) - } - - envStore := newEnvStore() - envStore.Record(tc.env.Name) - - s.Equal(tc.expectedEnvStore, envStore) - - if tc.env.Exists { - s.NoError(os.Unsetenv(tc.env.Name)) - } - }) - } -} - -func (s *EnvStoreTestSuite) TestRestore() { - testCases := []struct { - name string - env Env - expectedEnvValue string - expectedEnvExists bool - }{ - { - name: "exists env", - env: Env{ - Name: "name", - Value: "value", - Exists: true, - }, - expectedEnvValue: "value", - expectedEnvExists: true, - }, - { - name: "no exists env", - env: Env{ - Name: "name", - Exists: false, - }, - expectedEnvExists: false, - }, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - envStore := newEnvStore() - envStore.add(tc.env) - - // Backup - backup := newEnvStore() - backup.Record(tc.env.Name) - - s.Require().NoError(os.Unsetenv(tc.env.Name)) - - s.NoError(envStore.Restore()) - v, exists := os.LookupEnv(tc.env.Name) - s.Equal(tc.expectedEnvValue, v) - s.Equal(tc.expectedEnvExists, exists) - - // Restore - s.Require().NoError(backup.Restore()) - }) - } -} - -func (s *EnvStoreTestSuite) Test_setEnv() { - testCases := []struct { - name string - key string - value string - expectedEnvStore *envStore - expectedEnvValue string - expectedEnvExists bool - }{ - { - name: "normal", - key: "name", - value: "value", - expectedEnvStore: &envStore{store: map[string]Env{ - "name": { - Name: "name", - Value: "other value", - Exists: true, - }, - }}, - expectedEnvValue: "value", - expectedEnvExists: true, - }, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - envStore := newEnvStore() - - // Backup - backup := newEnvStore() - backup.Record(tc.key) - - s.Require().NoError(os.Setenv(tc.key, "other value")) - - s.NoError(envStore.setEnv(tc.key, tc.value)) - s.Equal(tc.expectedEnvStore, envStore) - v, exists := os.LookupEnv(tc.key) - s.Equal(tc.expectedEnvValue, v) - s.Equal(tc.expectedEnvExists, exists) - - // Restore - s.Require().NoError(backup.Restore()) - }) - } -} - -func TestEnvStoreTestSuite(t *testing.T) { - suite.Run(t, new(EnvStoreTestSuite)) -} - -func TestSetEnvVariables(t *testing.T) { - envs := map[string]string{ - "name1": "value1", - "name2": "value2", - } - - // Backup - backup := newEnvStore() - for k := range envs { - backup.Record(k) - } - defer func() { - require.NoError(t, backup.Restore()) - }() - - store, err := SetEnvVariables(envs) - assert.NoError(t, err) - require.IsType(t, &envStore{}, store) - concreteStore := store.(*envStore) - assert.Len(t, concreteStore.store, 2) - assert.Equal(t, backup, concreteStore) -} diff --git a/internal/shared/internaltest/errors.go.tmpl b/internal/shared/internaltest/errors.go.tmpl deleted file mode 100644 index 670203bdc..000000000 --- a/internal/shared/internaltest/errors.go.tmpl +++ /dev/null @@ -1,19 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/errors.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package internaltest - -type TestError string - -var _ error = TestError("") - -func NewTestError(s string) error { - return TestError(s) -} - -func (e TestError) Error() string { - return string(e) -} diff --git a/internal/shared/internaltest/harness.go.tmpl b/internal/shared/internaltest/harness.go.tmpl deleted file mode 100644 index a7c0695d2..000000000 --- a/internal/shared/internaltest/harness.go.tmpl +++ /dev/null @@ -1,334 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/harness.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package internaltest - -import ( - "context" - "fmt" - "strconv" - "sync" - "testing" - "time" - - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/codes" - "{{ .matchersImportPath }}" - "go.opentelemetry.io/otel/trace" -) - -// Harness is a testing harness used to test implementations of the -// OpenTelemetry API. -type Harness struct { - t *testing.T -} - -// NewHarness returns an instantiated *Harness using t. -func NewHarness(t *testing.T) *Harness { - return &Harness{ - t: t, - } -} - -// TestTracerProvider runs validation tests for an implementation of the OpenTelemetry -// TracerProvider API. -func (h *Harness) TestTracerProvider(subjectFactory func() trace.TracerProvider) { - h.t.Run("#Start", func(t *testing.T) { - t.Run("allow creating an arbitrary number of TracerProvider instances", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - - tp1 := subjectFactory() - tp2 := subjectFactory() - - e.Expect(tp1).NotToEqual(tp2) - }) - t.Run("all methods are safe to be called concurrently", func(t *testing.T) { - t.Parallel() - - runner := func(tp trace.TracerProvider) <-chan struct{} { - done := make(chan struct{}) - go func(tp trace.TracerProvider) { - var wg sync.WaitGroup - for i := 0; i < 20; i++ { - wg.Add(1) - go func(name, version string) { - _ = tp.Tracer(name, trace.WithInstrumentationVersion(version)) - wg.Done() - }(fmt.Sprintf("tracer %d", i%5), strconv.Itoa(i)) - } - wg.Wait() - done <- struct{}{} - }(tp) - return done - } - - matchers.NewExpecter(t).Expect(func() { - // Run with multiple TracerProvider to ensure they encapsulate - // their own Tracers. - tp1 := subjectFactory() - tp2 := subjectFactory() - - done1 := runner(tp1) - done2 := runner(tp2) - - <-done1 - <-done2 - }).NotToPanic() - }) - }) -} - -// TestTracer runs validation tests for an implementation of the OpenTelemetry -// Tracer API. -func (h *Harness) TestTracer(subjectFactory func() trace.Tracer) { - h.t.Run("#Start", func(t *testing.T) { - t.Run("propagates the original context", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - subject := subjectFactory() - - ctxKey := testCtxKey{} - ctxValue := "ctx value" - ctx := context.WithValue(context.Background(), ctxKey, ctxValue) - - ctx, _ = subject.Start(ctx, "test") - - e.Expect(ctx.Value(ctxKey)).ToEqual(ctxValue) - }) - - t.Run("returns a span containing the expected properties", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - subject := subjectFactory() - - _, span := subject.Start(context.Background(), "test") - - e.Expect(span).NotToBeNil() - - e.Expect(span.SpanContext().IsValid()).ToBeTrue() - }) - - t.Run("stores the span on the provided context", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - subject := subjectFactory() - - ctx, span := subject.Start(context.Background(), "test") - - e.Expect(span).NotToBeNil() - e.Expect(span.SpanContext()).NotToEqual(trace.SpanContext{}) - e.Expect(trace.SpanFromContext(ctx)).ToEqual(span) - }) - - t.Run("starts spans with unique trace and span IDs", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - subject := subjectFactory() - - _, span1 := subject.Start(context.Background(), "span1") - _, span2 := subject.Start(context.Background(), "span2") - - sc1 := span1.SpanContext() - sc2 := span2.SpanContext() - - e.Expect(sc1.TraceID()).NotToEqual(sc2.TraceID()) - e.Expect(sc1.SpanID()).NotToEqual(sc2.SpanID()) - }) - - t.Run("propagates a parent's trace ID through the context", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - subject := subjectFactory() - - ctx, parent := subject.Start(context.Background(), "parent") - _, child := subject.Start(ctx, "child") - - psc := parent.SpanContext() - csc := child.SpanContext() - - e.Expect(csc.TraceID()).ToEqual(psc.TraceID()) - e.Expect(csc.SpanID()).NotToEqual(psc.SpanID()) - }) - - t.Run("ignores parent's trace ID when new root is requested", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - subject := subjectFactory() - - ctx, parent := subject.Start(context.Background(), "parent") - _, child := subject.Start(ctx, "child", trace.WithNewRoot()) - - psc := parent.SpanContext() - csc := child.SpanContext() - - e.Expect(csc.TraceID()).NotToEqual(psc.TraceID()) - e.Expect(csc.SpanID()).NotToEqual(psc.SpanID()) - }) - - t.Run("propagates remote parent's trace ID through the context", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - subject := subjectFactory() - - _, remoteParent := subject.Start(context.Background(), "remote parent") - parentCtx := trace.ContextWithRemoteSpanContext(context.Background(), remoteParent.SpanContext()) - _, child := subject.Start(parentCtx, "child") - - psc := remoteParent.SpanContext() - csc := child.SpanContext() - - e.Expect(csc.TraceID()).ToEqual(psc.TraceID()) - e.Expect(csc.SpanID()).NotToEqual(psc.SpanID()) - }) - - t.Run("ignores remote parent's trace ID when new root is requested", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - subject := subjectFactory() - - _, remoteParent := subject.Start(context.Background(), "remote parent") - parentCtx := trace.ContextWithRemoteSpanContext(context.Background(), remoteParent.SpanContext()) - _, child := subject.Start(parentCtx, "child", trace.WithNewRoot()) - - psc := remoteParent.SpanContext() - csc := child.SpanContext() - - e.Expect(csc.TraceID()).NotToEqual(psc.TraceID()) - e.Expect(csc.SpanID()).NotToEqual(psc.SpanID()) - }) - - t.Run("all methods are safe to be called concurrently", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - tracer := subjectFactory() - - ctx, parent := tracer.Start(context.Background(), "span") - - runner := func(tp trace.Tracer) <-chan struct{} { - done := make(chan struct{}) - go func(tp trace.Tracer) { - var wg sync.WaitGroup - for i := 0; i < 20; i++ { - wg.Add(1) - go func(name string) { - defer wg.Done() - _, child := tp.Start(ctx, name) - - psc := parent.SpanContext() - csc := child.SpanContext() - - e.Expect(csc.TraceID()).ToEqual(psc.TraceID()) - e.Expect(csc.SpanID()).NotToEqual(psc.SpanID()) - }(fmt.Sprintf("span %d", i)) - } - wg.Wait() - done <- struct{}{} - }(tp) - return done - } - - e.Expect(func() { - done := runner(tracer) - - <-done - }).NotToPanic() - }) - }) - - h.testSpan(subjectFactory) -} - -func (h *Harness) testSpan(tracerFactory func() trace.Tracer) { - methods := map[string]func(span trace.Span){ - "#End": func(span trace.Span) { - span.End() - }, - "#AddEvent": func(span trace.Span) { - span.AddEvent("test event") - }, - "#AddEventWithTimestamp": func(span trace.Span) { - span.AddEvent("test event", trace.WithTimestamp(time.Now().Add(1*time.Second))) - }, - "#SetStatus": func(span trace.Span) { - span.SetStatus(codes.Error, "internal") - }, - "#SetName": func(span trace.Span) { - span.SetName("new name") - }, - "#SetAttributes": func(span trace.Span) { - span.SetAttributes(attribute.String("key1", "value"), attribute.Int("key2", 123)) - }, - } - mechanisms := map[string]func() trace.Span{ - "Span created via Tracer#Start": func() trace.Span { - tracer := tracerFactory() - _, subject := tracer.Start(context.Background(), "test") - - return subject - }, - "Span created via span.TracerProvider()": func() trace.Span { - ctx, spanA := tracerFactory().Start(context.Background(), "span1") - - _, spanB := spanA.TracerProvider().Tracer("second").Start(ctx, "span2") - return spanB - }, - } - - for mechanismName, mechanism := range mechanisms { - h.t.Run(mechanismName, func(t *testing.T) { - for methodName, method := range methods { - t.Run(methodName, func(t *testing.T) { - t.Run("is thread-safe", func(t *testing.T) { - t.Parallel() - - span := mechanism() - - wg := &sync.WaitGroup{} - wg.Add(2) - - go func() { - defer wg.Done() - - method(span) - }() - - go func() { - defer wg.Done() - - method(span) - }() - - wg.Wait() - }) - }) - } - - t.Run("#End", func(t *testing.T) { - t.Run("can be called multiple times", func(t *testing.T) { - t.Parallel() - - span := mechanism() - - span.End() - span.End() - }) - }) - }) - } -} - -type testCtxKey struct{} diff --git a/internal/shared/internaltest/text_map_carrier.go.tmpl b/internal/shared/internaltest/text_map_carrier.go.tmpl deleted file mode 100644 index dff8f94c5..000000000 --- a/internal/shared/internaltest/text_map_carrier.go.tmpl +++ /dev/null @@ -1,133 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/text_map_carrier.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package internaltest - -import ( - "sync" - "testing" - - "go.opentelemetry.io/otel/propagation" -) - -// TextMapCarrier is a storage medium for a TextMapPropagator used in testing. -// The methods of a TextMapCarrier are concurrent safe. -type TextMapCarrier struct { - mtx sync.Mutex - - gets []string - sets [][2]string - data map[string]string -} - -var _ propagation.TextMapCarrier = (*TextMapCarrier)(nil) - -// NewTextMapCarrier returns a new *TextMapCarrier populated with data. -func NewTextMapCarrier(data map[string]string) *TextMapCarrier { - copied := make(map[string]string, len(data)) - for k, v := range data { - copied[k] = v - } - return &TextMapCarrier{data: copied} -} - -// Keys returns the keys for which this carrier has a value. -func (c *TextMapCarrier) Keys() []string { - c.mtx.Lock() - defer c.mtx.Unlock() - - result := make([]string, 0, len(c.data)) - for k := range c.data { - result = append(result, k) - } - return result -} - -// Get returns the value associated with the passed key. -func (c *TextMapCarrier) Get(key string) string { - c.mtx.Lock() - defer c.mtx.Unlock() - c.gets = append(c.gets, key) - return c.data[key] -} - -// GotKey tests if c.Get has been called for key. -func (c *TextMapCarrier) GotKey(t *testing.T, key string) bool { - c.mtx.Lock() - defer c.mtx.Unlock() - for _, k := range c.gets { - if k == key { - return true - } - } - t.Errorf("TextMapCarrier.Get(%q) has not been called", key) - return false -} - -// GotN tests if n calls to c.Get have been made. -func (c *TextMapCarrier) GotN(t *testing.T, n int) bool { - c.mtx.Lock() - defer c.mtx.Unlock() - if len(c.gets) != n { - t.Errorf("TextMapCarrier.Get was called %d times, not %d", len(c.gets), n) - return false - } - return true -} - -// Set stores the key-value pair. -func (c *TextMapCarrier) Set(key, value string) { - c.mtx.Lock() - defer c.mtx.Unlock() - c.sets = append(c.sets, [2]string{key, value}) - c.data[key] = value -} - -// SetKeyValue tests if c.Set has been called for the key-value pair. -func (c *TextMapCarrier) SetKeyValue(t *testing.T, key, value string) bool { - c.mtx.Lock() - defer c.mtx.Unlock() - var vals []string - for _, pair := range c.sets { - if key == pair[0] { - if value == pair[1] { - return true - } - vals = append(vals, pair[1]) - } - } - if len(vals) > 0 { - t.Errorf("TextMapCarrier.Set called with %q and %v values, but not %s", key, vals, value) - } - t.Errorf("TextMapCarrier.Set(%q,%q) has not been called", key, value) - return false -} - -// SetN tests if n calls to c.Set have been made. -func (c *TextMapCarrier) SetN(t *testing.T, n int) bool { - c.mtx.Lock() - defer c.mtx.Unlock() - if len(c.sets) != n { - t.Errorf("TextMapCarrier.Set was called %d times, not %d", len(c.sets), n) - return false - } - return true -} - -// Reset zeros out the recording state and sets the carried values to data. -func (c *TextMapCarrier) Reset(data map[string]string) { - copied := make(map[string]string, len(data)) - for k, v := range data { - copied[k] = v - } - - c.mtx.Lock() - defer c.mtx.Unlock() - - c.gets = nil - c.sets = nil - c.data = copied -} diff --git a/internal/shared/internaltest/text_map_carrier_test.go.tmpl b/internal/shared/internaltest/text_map_carrier_test.go.tmpl deleted file mode 100644 index a4c233564..000000000 --- a/internal/shared/internaltest/text_map_carrier_test.go.tmpl +++ /dev/null @@ -1,73 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/text_map_carrier_test.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package internaltest - -import ( - "reflect" - "testing" -) - -var key, value = "test", "true" - -func TestTextMapCarrierKeys(t *testing.T) { - tmc := NewTextMapCarrier(map[string]string{key: value}) - expected, actual := []string{key}, tmc.Keys() - if !reflect.DeepEqual(actual, expected) { - t.Errorf("expected tmc.Keys() to be %v but it was %v", expected, actual) - } -} - -func TestTextMapCarrierGet(t *testing.T) { - tmc := NewTextMapCarrier(map[string]string{key: value}) - tmc.GotN(t, 0) - if got := tmc.Get("empty"); got != "" { - t.Errorf("TextMapCarrier.Get returned %q for an empty key", got) - } - tmc.GotKey(t, "empty") - tmc.GotN(t, 1) - if got := tmc.Get(key); got != value { - t.Errorf("TextMapCarrier.Get(%q) returned %q, want %q", key, got, value) - } - tmc.GotKey(t, key) - tmc.GotN(t, 2) -} - -func TestTextMapCarrierSet(t *testing.T) { - tmc := NewTextMapCarrier(nil) - tmc.SetN(t, 0) - tmc.Set(key, value) - if got, ok := tmc.data[key]; !ok { - t.Errorf("TextMapCarrier.Set(%q,%q) failed to store pair", key, value) - } else if got != value { - t.Errorf("TextMapCarrier.Set(%q,%q) stored (%q,%q), not (%q,%q)", key, value, key, got, key, value) - } - tmc.SetKeyValue(t, key, value) - tmc.SetN(t, 1) -} - -func TestTextMapCarrierReset(t *testing.T) { - tmc := NewTextMapCarrier(map[string]string{key: value}) - tmc.GotN(t, 0) - tmc.SetN(t, 0) - tmc.Reset(nil) - tmc.GotN(t, 0) - tmc.SetN(t, 0) - if got := tmc.Get(key); got != "" { - t.Error("TextMapCarrier.Reset() failed to clear initial data") - } - tmc.GotN(t, 1) - tmc.GotKey(t, key) - tmc.Set(key, value) - tmc.SetKeyValue(t, key, value) - tmc.SetN(t, 1) - tmc.Reset(nil) - tmc.GotN(t, 0) - tmc.SetN(t, 0) - if got := tmc.Get(key); got != "" { - t.Error("TextMapCarrier.Reset() failed to clear data") - } -} diff --git a/internal/shared/internaltest/text_map_propagator.go.tmpl b/internal/shared/internaltest/text_map_propagator.go.tmpl deleted file mode 100644 index fccf54043..000000000 --- a/internal/shared/internaltest/text_map_propagator.go.tmpl +++ /dev/null @@ -1,104 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/text_map_propagator.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package internaltest - -import ( - "context" - "fmt" - "strconv" - "strings" - "testing" - - "go.opentelemetry.io/otel/propagation" -) - -type ctxKeyType string - -type state struct { - Injections uint64 - Extractions uint64 -} - -func newState(encoded string) state { - if encoded == "" { - return state{} - } - s0, s1, _ := strings.Cut(encoded, ",") - injects, _ := strconv.ParseUint(s0, 10, 64) - extracts, _ := strconv.ParseUint(s1, 10, 64) - return state{ - Injections: injects, - Extractions: extracts, - } -} - -func (s state) String() string { - return fmt.Sprintf("%d,%d", s.Injections, s.Extractions) -} - -// TextMapPropagator is a propagation.TextMapPropagator used for testing. -type TextMapPropagator struct { - name string - ctxKey ctxKeyType -} - -var _ propagation.TextMapPropagator = (*TextMapPropagator)(nil) - -// NewTextMapPropagator returns a new TextMapPropagator for testing. It will -// use name as the key it injects into a TextMapCarrier when Inject is called. -func NewTextMapPropagator(name string) *TextMapPropagator { - return &TextMapPropagator{name: name, ctxKey: ctxKeyType(name)} -} - -func (p *TextMapPropagator) stateFromContext(ctx context.Context) state { - if v := ctx.Value(p.ctxKey); v != nil { - if s, ok := v.(state); ok { - return s - } - } - return state{} -} - -func (p *TextMapPropagator) stateFromCarrier(carrier propagation.TextMapCarrier) state { - return newState(carrier.Get(p.name)) -} - -// Inject sets cross-cutting concerns for p from ctx into carrier. -func (p *TextMapPropagator) Inject(ctx context.Context, carrier propagation.TextMapCarrier) { - s := p.stateFromContext(ctx) - s.Injections++ - carrier.Set(p.name, s.String()) -} - -// InjectedN tests if p has made n injections to carrier. -func (p *TextMapPropagator) InjectedN(t *testing.T, carrier *TextMapCarrier, n uint64) bool { - if actual := p.stateFromCarrier(carrier).Injections; actual != n { - t.Errorf("TextMapPropagator{%q} injected %d times, not %d", p.name, actual, n) - return false - } - return true -} - -// Extract reads cross-cutting concerns for p from carrier into ctx. -func (p *TextMapPropagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context { - s := p.stateFromCarrier(carrier) - s.Extractions++ - return context.WithValue(ctx, p.ctxKey, s) -} - -// ExtractedN tests if p has made n extractions from the lineage of ctx. -// nolint (context is not first arg) -func (p *TextMapPropagator) ExtractedN(t *testing.T, ctx context.Context, n int) bool { - if actual := p.stateFromContext(ctx).Extractions; actual != uint64(n) { - t.Errorf("TextMapPropagator{%q} extracted %d time, not %d", p.name, actual, n) - return false - } - return true -} - -// Fields returns the name of p as the key who's value is set with Inject. -func (p *TextMapPropagator) Fields() []string { return []string{p.name} } diff --git a/internal/shared/internaltest/text_map_propagator_test.go.tmpl b/internal/shared/internaltest/text_map_propagator_test.go.tmpl deleted file mode 100644 index 67002ec83..000000000 --- a/internal/shared/internaltest/text_map_propagator_test.go.tmpl +++ /dev/null @@ -1,61 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/text_map_propagator_test.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package internaltest - -import ( - "context" - "testing" -) - -func TestTextMapPropagatorInjectExtract(t *testing.T) { - name := "testing" - ctx := context.Background() - carrier := NewTextMapCarrier(map[string]string{name: value}) - propagator := NewTextMapPropagator(name) - - propagator.Inject(ctx, carrier) - // Carrier value overridden with state. - if carrier.SetKeyValue(t, name, "1,0") { - // Ensure nothing has been extracted yet. - propagator.ExtractedN(t, ctx, 0) - // Test the injection was counted. - propagator.InjectedN(t, carrier, 1) - } - - ctx = propagator.Extract(ctx, carrier) - v := ctx.Value(ctxKeyType(name)) - if v == nil { - t.Error("TextMapPropagator.Extract failed to extract state") - } - if s, ok := v.(state); !ok { - t.Error("TextMapPropagator.Extract did not extract proper state") - } else if s.Extractions != 1 { - t.Error("TextMapPropagator.Extract did not increment state.Extractions") - } - if carrier.GotKey(t, name) { - // Test the extraction was counted. - propagator.ExtractedN(t, ctx, 1) - // Ensure no additional injection was recorded. - propagator.InjectedN(t, carrier, 1) - } -} - -func TestTextMapPropagatorFields(t *testing.T) { - name := "testing" - propagator := NewTextMapPropagator(name) - if got := propagator.Fields(); len(got) != 1 { - t.Errorf("TextMapPropagator.Fields returned %d fields, want 1", len(got)) - } else if got[0] != name { - t.Errorf("TextMapPropagator.Fields returned %q, want %q", got[0], name) - } -} - -func TestNewStateEmpty(t *testing.T) { - if want, got := (state{}), newState(""); got != want { - t.Errorf("newState(\"\") returned %v, want %v", got, want) - } -} diff --git a/sdk/internal/env/env_test.go b/sdk/internal/env/env_test.go index 2f154884e..191894aad 100644 --- a/sdk/internal/env/env_test.go +++ b/sdk/internal/env/env_test.go @@ -7,9 +7,6 @@ import ( "testing" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - ottest "go.opentelemetry.io/otel/sdk/internal/internaltest" ) func TestEnvParse(t *testing.T) { @@ -91,10 +88,6 @@ func TestEnvParse(t *testing.T) { t.Run(tc.name, func(t *testing.T) { for _, key := range tc.keys { t.Run(key, func(t *testing.T) { - envStore := ottest.NewEnvStore() - t.Cleanup(func() { require.NoError(t, envStore.Restore()) }) - envStore.Record(key) - assert.Equal(t, defVal, tc.f(defVal), "environment variable unset") t.Setenv(key, envValStr) diff --git a/sdk/internal/gen.go b/sdk/internal/gen.go index 402d92c96..b0b67896b 100644 --- a/sdk/internal/gen.go +++ b/sdk/internal/gen.go @@ -7,13 +7,3 @@ package internal // import "go.opentelemetry.io/otel/sdk/internal" //go:generate gotmpl --body=../../internal/shared/matchers/expectation.go.tmpl "--data={}" --out=matchers/expectation.go //go:generate gotmpl --body=../../internal/shared/matchers/expecter.go.tmpl "--data={}" --out=matchers/expecter.go //go:generate gotmpl --body=../../internal/shared/matchers/temporal_matcher.go.tmpl "--data={}" --out=matchers/temporal_matcher.go - -//go:generate gotmpl --body=../../internal/shared/internaltest/doc.go.tmpl "--data={}" --out=internaltest/doc.go -//go:generate gotmpl --body=../../internal/shared/internaltest/env.go.tmpl "--data={}" --out=internaltest/env.go -//go:generate gotmpl --body=../../internal/shared/internaltest/env_test.go.tmpl "--data={}" --out=internaltest/env_test.go -//go:generate gotmpl --body=../../internal/shared/internaltest/errors.go.tmpl "--data={}" --out=internaltest/errors.go -//go:generate gotmpl --body=../../internal/shared/internaltest/harness.go.tmpl "--data={\"matchersImportPath\": \"go.opentelemetry.io/otel/sdk/internal/matchers\"}" --out=internaltest/harness.go -//go:generate gotmpl --body=../../internal/shared/internaltest/text_map_carrier.go.tmpl "--data={}" --out=internaltest/text_map_carrier.go -//go:generate gotmpl --body=../../internal/shared/internaltest/text_map_carrier_test.go.tmpl "--data={}" --out=internaltest/text_map_carrier_test.go -//go:generate gotmpl --body=../../internal/shared/internaltest/text_map_propagator.go.tmpl "--data={}" --out=internaltest/text_map_propagator.go -//go:generate gotmpl --body=../../internal/shared/internaltest/text_map_propagator_test.go.tmpl "--data={}" --out=internaltest/text_map_propagator_test.go diff --git a/sdk/internal/internaltest/doc.go b/sdk/internal/internaltest/doc.go deleted file mode 100644 index 13e58fe20..000000000 --- a/sdk/internal/internaltest/doc.go +++ /dev/null @@ -1,8 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/doc.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -// Package internaltest provides testing functionality. -package internaltest // import "go.opentelemetry.io/otel/sdk/internal/internaltest" diff --git a/sdk/internal/internaltest/env.go b/sdk/internal/internaltest/env.go deleted file mode 100644 index 9e95a1b6b..000000000 --- a/sdk/internal/internaltest/env.go +++ /dev/null @@ -1,90 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/env.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package internaltest // import "go.opentelemetry.io/otel/sdk/internal/internaltest" - -import ( - "os" -) - -type Env struct { - Name string - Value string - Exists bool -} - -// EnvStore stores and recovers environment variables. -type EnvStore interface { - // Records the environment variable into the store. - Record(key string) - - // Restore recovers the environment variables in the store. - Restore() error -} - -var _ EnvStore = (*envStore)(nil) - -type envStore struct { - store map[string]Env -} - -func (s *envStore) add(env Env) { - s.store[env.Name] = env -} - -func (s *envStore) Restore() error { - var err error - for _, v := range s.store { - if v.Exists { - err = os.Setenv(v.Name, v.Value) - } else { - err = os.Unsetenv(v.Name) - } - if err != nil { - return err - } - } - return nil -} - -func (s *envStore) setEnv(key, value string) error { - s.Record(key) - - err := os.Setenv(key, value) - if err != nil { - return err - } - return nil -} - -func (s *envStore) Record(key string) { - originValue, exists := os.LookupEnv(key) - s.add(Env{ - Name: key, - Value: originValue, - Exists: exists, - }) -} - -func NewEnvStore() EnvStore { - return newEnvStore() -} - -func newEnvStore() *envStore { - return &envStore{store: make(map[string]Env)} -} - -func SetEnvVariables(env map[string]string) (EnvStore, error) { - envStore := newEnvStore() - - for k, v := range env { - err := envStore.setEnv(k, v) - if err != nil { - return nil, err - } - } - return envStore, nil -} diff --git a/sdk/internal/internaltest/env_test.go b/sdk/internal/internaltest/env_test.go deleted file mode 100644 index 093d06812..000000000 --- a/sdk/internal/internaltest/env_test.go +++ /dev/null @@ -1,226 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/env_test.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package internaltest - -import ( - "os" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/stretchr/testify/suite" -) - -type EnvStoreTestSuite struct { - suite.Suite -} - -func (s *EnvStoreTestSuite) Test_add() { - envStore := newEnvStore() - - e := Env{ - Name: "name", - Value: "value", - Exists: true, - } - envStore.add(e) - envStore.add(e) - - s.Len(envStore.store, 1) -} - -func (s *EnvStoreTestSuite) TestRecord() { - testCases := []struct { - name string - env Env - expectedEnvStore *envStore - }{ - { - name: "record exists env", - env: Env{ - Name: "name", - Value: "value", - Exists: true, - }, - expectedEnvStore: &envStore{store: map[string]Env{ - "name": { - Name: "name", - Value: "value", - Exists: true, - }, - }}, - }, - { - name: "record exists env, but its value is empty", - env: Env{ - Name: "name", - Value: "", - Exists: true, - }, - expectedEnvStore: &envStore{store: map[string]Env{ - "name": { - Name: "name", - Value: "", - Exists: true, - }, - }}, - }, - { - name: "record not exists env", - env: Env{ - Name: "name", - Exists: false, - }, - expectedEnvStore: &envStore{store: map[string]Env{ - "name": { - Name: "name", - Exists: false, - }, - }}, - }, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - if tc.env.Exists { - s.NoError(os.Setenv(tc.env.Name, tc.env.Value)) - } - - envStore := newEnvStore() - envStore.Record(tc.env.Name) - - s.Equal(tc.expectedEnvStore, envStore) - - if tc.env.Exists { - s.NoError(os.Unsetenv(tc.env.Name)) - } - }) - } -} - -func (s *EnvStoreTestSuite) TestRestore() { - testCases := []struct { - name string - env Env - expectedEnvValue string - expectedEnvExists bool - }{ - { - name: "exists env", - env: Env{ - Name: "name", - Value: "value", - Exists: true, - }, - expectedEnvValue: "value", - expectedEnvExists: true, - }, - { - name: "no exists env", - env: Env{ - Name: "name", - Exists: false, - }, - expectedEnvExists: false, - }, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - envStore := newEnvStore() - envStore.add(tc.env) - - // Backup - backup := newEnvStore() - backup.Record(tc.env.Name) - - s.Require().NoError(os.Unsetenv(tc.env.Name)) - - s.NoError(envStore.Restore()) - v, exists := os.LookupEnv(tc.env.Name) - s.Equal(tc.expectedEnvValue, v) - s.Equal(tc.expectedEnvExists, exists) - - // Restore - s.Require().NoError(backup.Restore()) - }) - } -} - -func (s *EnvStoreTestSuite) Test_setEnv() { - testCases := []struct { - name string - key string - value string - expectedEnvStore *envStore - expectedEnvValue string - expectedEnvExists bool - }{ - { - name: "normal", - key: "name", - value: "value", - expectedEnvStore: &envStore{store: map[string]Env{ - "name": { - Name: "name", - Value: "other value", - Exists: true, - }, - }}, - expectedEnvValue: "value", - expectedEnvExists: true, - }, - } - - for _, tc := range testCases { - s.Run(tc.name, func() { - envStore := newEnvStore() - - // Backup - backup := newEnvStore() - backup.Record(tc.key) - - s.Require().NoError(os.Setenv(tc.key, "other value")) - - s.NoError(envStore.setEnv(tc.key, tc.value)) - s.Equal(tc.expectedEnvStore, envStore) - v, exists := os.LookupEnv(tc.key) - s.Equal(tc.expectedEnvValue, v) - s.Equal(tc.expectedEnvExists, exists) - - // Restore - s.Require().NoError(backup.Restore()) - }) - } -} - -func TestEnvStoreTestSuite(t *testing.T) { - suite.Run(t, new(EnvStoreTestSuite)) -} - -func TestSetEnvVariables(t *testing.T) { - envs := map[string]string{ - "name1": "value1", - "name2": "value2", - } - - // Backup - backup := newEnvStore() - for k := range envs { - backup.Record(k) - } - defer func() { - require.NoError(t, backup.Restore()) - }() - - store, err := SetEnvVariables(envs) - assert.NoError(t, err) - require.IsType(t, &envStore{}, store) - concreteStore := store.(*envStore) - assert.Len(t, concreteStore.store, 2) - assert.Equal(t, backup, concreteStore) -} diff --git a/sdk/internal/internaltest/errors.go b/sdk/internal/internaltest/errors.go deleted file mode 100644 index a800e0ba1..000000000 --- a/sdk/internal/internaltest/errors.go +++ /dev/null @@ -1,19 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/errors.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package internaltest // import "go.opentelemetry.io/otel/sdk/internal/internaltest" - -type TestError string - -var _ error = TestError("") - -func NewTestError(s string) error { - return TestError(s) -} - -func (e TestError) Error() string { - return string(e) -} diff --git a/sdk/internal/internaltest/harness.go b/sdk/internal/internaltest/harness.go deleted file mode 100644 index 34eab50f6..000000000 --- a/sdk/internal/internaltest/harness.go +++ /dev/null @@ -1,334 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/harness.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package internaltest // import "go.opentelemetry.io/otel/sdk/internal/internaltest" - -import ( - "context" - "fmt" - "strconv" - "sync" - "testing" - "time" - - "go.opentelemetry.io/otel/attribute" - "go.opentelemetry.io/otel/codes" - "go.opentelemetry.io/otel/sdk/internal/matchers" - "go.opentelemetry.io/otel/trace" -) - -// Harness is a testing harness used to test implementations of the -// OpenTelemetry API. -type Harness struct { - t *testing.T -} - -// NewHarness returns an instantiated *Harness using t. -func NewHarness(t *testing.T) *Harness { - return &Harness{ - t: t, - } -} - -// TestTracerProvider runs validation tests for an implementation of the OpenTelemetry -// TracerProvider API. -func (h *Harness) TestTracerProvider(subjectFactory func() trace.TracerProvider) { - h.t.Run("#Start", func(t *testing.T) { - t.Run("allow creating an arbitrary number of TracerProvider instances", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - - tp1 := subjectFactory() - tp2 := subjectFactory() - - e.Expect(tp1).NotToEqual(tp2) - }) - t.Run("all methods are safe to be called concurrently", func(t *testing.T) { - t.Parallel() - - runner := func(tp trace.TracerProvider) <-chan struct{} { - done := make(chan struct{}) - go func(tp trace.TracerProvider) { - var wg sync.WaitGroup - for i := 0; i < 20; i++ { - wg.Add(1) - go func(name, version string) { - _ = tp.Tracer(name, trace.WithInstrumentationVersion(version)) - wg.Done() - }(fmt.Sprintf("tracer %d", i%5), strconv.Itoa(i)) - } - wg.Wait() - done <- struct{}{} - }(tp) - return done - } - - matchers.NewExpecter(t).Expect(func() { - // Run with multiple TracerProvider to ensure they encapsulate - // their own Tracers. - tp1 := subjectFactory() - tp2 := subjectFactory() - - done1 := runner(tp1) - done2 := runner(tp2) - - <-done1 - <-done2 - }).NotToPanic() - }) - }) -} - -// TestTracer runs validation tests for an implementation of the OpenTelemetry -// Tracer API. -func (h *Harness) TestTracer(subjectFactory func() trace.Tracer) { - h.t.Run("#Start", func(t *testing.T) { - t.Run("propagates the original context", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - subject := subjectFactory() - - ctxKey := testCtxKey{} - ctxValue := "ctx value" - ctx := context.WithValue(context.Background(), ctxKey, ctxValue) - - ctx, _ = subject.Start(ctx, "test") - - e.Expect(ctx.Value(ctxKey)).ToEqual(ctxValue) - }) - - t.Run("returns a span containing the expected properties", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - subject := subjectFactory() - - _, span := subject.Start(context.Background(), "test") - - e.Expect(span).NotToBeNil() - - e.Expect(span.SpanContext().IsValid()).ToBeTrue() - }) - - t.Run("stores the span on the provided context", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - subject := subjectFactory() - - ctx, span := subject.Start(context.Background(), "test") - - e.Expect(span).NotToBeNil() - e.Expect(span.SpanContext()).NotToEqual(trace.SpanContext{}) - e.Expect(trace.SpanFromContext(ctx)).ToEqual(span) - }) - - t.Run("starts spans with unique trace and span IDs", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - subject := subjectFactory() - - _, span1 := subject.Start(context.Background(), "span1") - _, span2 := subject.Start(context.Background(), "span2") - - sc1 := span1.SpanContext() - sc2 := span2.SpanContext() - - e.Expect(sc1.TraceID()).NotToEqual(sc2.TraceID()) - e.Expect(sc1.SpanID()).NotToEqual(sc2.SpanID()) - }) - - t.Run("propagates a parent's trace ID through the context", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - subject := subjectFactory() - - ctx, parent := subject.Start(context.Background(), "parent") - _, child := subject.Start(ctx, "child") - - psc := parent.SpanContext() - csc := child.SpanContext() - - e.Expect(csc.TraceID()).ToEqual(psc.TraceID()) - e.Expect(csc.SpanID()).NotToEqual(psc.SpanID()) - }) - - t.Run("ignores parent's trace ID when new root is requested", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - subject := subjectFactory() - - ctx, parent := subject.Start(context.Background(), "parent") - _, child := subject.Start(ctx, "child", trace.WithNewRoot()) - - psc := parent.SpanContext() - csc := child.SpanContext() - - e.Expect(csc.TraceID()).NotToEqual(psc.TraceID()) - e.Expect(csc.SpanID()).NotToEqual(psc.SpanID()) - }) - - t.Run("propagates remote parent's trace ID through the context", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - subject := subjectFactory() - - _, remoteParent := subject.Start(context.Background(), "remote parent") - parentCtx := trace.ContextWithRemoteSpanContext(context.Background(), remoteParent.SpanContext()) - _, child := subject.Start(parentCtx, "child") - - psc := remoteParent.SpanContext() - csc := child.SpanContext() - - e.Expect(csc.TraceID()).ToEqual(psc.TraceID()) - e.Expect(csc.SpanID()).NotToEqual(psc.SpanID()) - }) - - t.Run("ignores remote parent's trace ID when new root is requested", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - subject := subjectFactory() - - _, remoteParent := subject.Start(context.Background(), "remote parent") - parentCtx := trace.ContextWithRemoteSpanContext(context.Background(), remoteParent.SpanContext()) - _, child := subject.Start(parentCtx, "child", trace.WithNewRoot()) - - psc := remoteParent.SpanContext() - csc := child.SpanContext() - - e.Expect(csc.TraceID()).NotToEqual(psc.TraceID()) - e.Expect(csc.SpanID()).NotToEqual(psc.SpanID()) - }) - - t.Run("all methods are safe to be called concurrently", func(t *testing.T) { - t.Parallel() - - e := matchers.NewExpecter(t) - tracer := subjectFactory() - - ctx, parent := tracer.Start(context.Background(), "span") - - runner := func(tp trace.Tracer) <-chan struct{} { - done := make(chan struct{}) - go func(tp trace.Tracer) { - var wg sync.WaitGroup - for i := 0; i < 20; i++ { - wg.Add(1) - go func(name string) { - defer wg.Done() - _, child := tp.Start(ctx, name) - - psc := parent.SpanContext() - csc := child.SpanContext() - - e.Expect(csc.TraceID()).ToEqual(psc.TraceID()) - e.Expect(csc.SpanID()).NotToEqual(psc.SpanID()) - }(fmt.Sprintf("span %d", i)) - } - wg.Wait() - done <- struct{}{} - }(tp) - return done - } - - e.Expect(func() { - done := runner(tracer) - - <-done - }).NotToPanic() - }) - }) - - h.testSpan(subjectFactory) -} - -func (h *Harness) testSpan(tracerFactory func() trace.Tracer) { - methods := map[string]func(span trace.Span){ - "#End": func(span trace.Span) { - span.End() - }, - "#AddEvent": func(span trace.Span) { - span.AddEvent("test event") - }, - "#AddEventWithTimestamp": func(span trace.Span) { - span.AddEvent("test event", trace.WithTimestamp(time.Now().Add(1*time.Second))) - }, - "#SetStatus": func(span trace.Span) { - span.SetStatus(codes.Error, "internal") - }, - "#SetName": func(span trace.Span) { - span.SetName("new name") - }, - "#SetAttributes": func(span trace.Span) { - span.SetAttributes(attribute.String("key1", "value"), attribute.Int("key2", 123)) - }, - } - mechanisms := map[string]func() trace.Span{ - "Span created via Tracer#Start": func() trace.Span { - tracer := tracerFactory() - _, subject := tracer.Start(context.Background(), "test") - - return subject - }, - "Span created via span.TracerProvider()": func() trace.Span { - ctx, spanA := tracerFactory().Start(context.Background(), "span1") - - _, spanB := spanA.TracerProvider().Tracer("second").Start(ctx, "span2") - return spanB - }, - } - - for mechanismName, mechanism := range mechanisms { - h.t.Run(mechanismName, func(t *testing.T) { - for methodName, method := range methods { - t.Run(methodName, func(t *testing.T) { - t.Run("is thread-safe", func(t *testing.T) { - t.Parallel() - - span := mechanism() - - wg := &sync.WaitGroup{} - wg.Add(2) - - go func() { - defer wg.Done() - - method(span) - }() - - go func() { - defer wg.Done() - - method(span) - }() - - wg.Wait() - }) - }) - } - - t.Run("#End", func(t *testing.T) { - t.Run("can be called multiple times", func(t *testing.T) { - t.Parallel() - - span := mechanism() - - span.End() - span.End() - }) - }) - }) - } -} - -type testCtxKey struct{} diff --git a/sdk/internal/internaltest/text_map_carrier.go b/sdk/internal/internaltest/text_map_carrier.go deleted file mode 100644 index 5972b3741..000000000 --- a/sdk/internal/internaltest/text_map_carrier.go +++ /dev/null @@ -1,133 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/text_map_carrier.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package internaltest // import "go.opentelemetry.io/otel/sdk/internal/internaltest" - -import ( - "sync" - "testing" - - "go.opentelemetry.io/otel/propagation" -) - -// TextMapCarrier is a storage medium for a TextMapPropagator used in testing. -// The methods of a TextMapCarrier are concurrent safe. -type TextMapCarrier struct { - mtx sync.Mutex - - gets []string - sets [][2]string - data map[string]string -} - -var _ propagation.TextMapCarrier = (*TextMapCarrier)(nil) - -// NewTextMapCarrier returns a new *TextMapCarrier populated with data. -func NewTextMapCarrier(data map[string]string) *TextMapCarrier { - copied := make(map[string]string, len(data)) - for k, v := range data { - copied[k] = v - } - return &TextMapCarrier{data: copied} -} - -// Keys returns the keys for which this carrier has a value. -func (c *TextMapCarrier) Keys() []string { - c.mtx.Lock() - defer c.mtx.Unlock() - - result := make([]string, 0, len(c.data)) - for k := range c.data { - result = append(result, k) - } - return result -} - -// Get returns the value associated with the passed key. -func (c *TextMapCarrier) Get(key string) string { - c.mtx.Lock() - defer c.mtx.Unlock() - c.gets = append(c.gets, key) - return c.data[key] -} - -// GotKey tests if c.Get has been called for key. -func (c *TextMapCarrier) GotKey(t *testing.T, key string) bool { - c.mtx.Lock() - defer c.mtx.Unlock() - for _, k := range c.gets { - if k == key { - return true - } - } - t.Errorf("TextMapCarrier.Get(%q) has not been called", key) - return false -} - -// GotN tests if n calls to c.Get have been made. -func (c *TextMapCarrier) GotN(t *testing.T, n int) bool { - c.mtx.Lock() - defer c.mtx.Unlock() - if len(c.gets) != n { - t.Errorf("TextMapCarrier.Get was called %d times, not %d", len(c.gets), n) - return false - } - return true -} - -// Set stores the key-value pair. -func (c *TextMapCarrier) Set(key, value string) { - c.mtx.Lock() - defer c.mtx.Unlock() - c.sets = append(c.sets, [2]string{key, value}) - c.data[key] = value -} - -// SetKeyValue tests if c.Set has been called for the key-value pair. -func (c *TextMapCarrier) SetKeyValue(t *testing.T, key, value string) bool { - c.mtx.Lock() - defer c.mtx.Unlock() - var vals []string - for _, pair := range c.sets { - if key == pair[0] { - if value == pair[1] { - return true - } - vals = append(vals, pair[1]) - } - } - if len(vals) > 0 { - t.Errorf("TextMapCarrier.Set called with %q and %v values, but not %s", key, vals, value) - } - t.Errorf("TextMapCarrier.Set(%q,%q) has not been called", key, value) - return false -} - -// SetN tests if n calls to c.Set have been made. -func (c *TextMapCarrier) SetN(t *testing.T, n int) bool { - c.mtx.Lock() - defer c.mtx.Unlock() - if len(c.sets) != n { - t.Errorf("TextMapCarrier.Set was called %d times, not %d", len(c.sets), n) - return false - } - return true -} - -// Reset zeros out the recording state and sets the carried values to data. -func (c *TextMapCarrier) Reset(data map[string]string) { - copied := make(map[string]string, len(data)) - for k, v := range data { - copied[k] = v - } - - c.mtx.Lock() - defer c.mtx.Unlock() - - c.gets = nil - c.sets = nil - c.data = copied -} diff --git a/sdk/internal/internaltest/text_map_carrier_test.go b/sdk/internal/internaltest/text_map_carrier_test.go deleted file mode 100644 index a4c233564..000000000 --- a/sdk/internal/internaltest/text_map_carrier_test.go +++ /dev/null @@ -1,73 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/text_map_carrier_test.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package internaltest - -import ( - "reflect" - "testing" -) - -var key, value = "test", "true" - -func TestTextMapCarrierKeys(t *testing.T) { - tmc := NewTextMapCarrier(map[string]string{key: value}) - expected, actual := []string{key}, tmc.Keys() - if !reflect.DeepEqual(actual, expected) { - t.Errorf("expected tmc.Keys() to be %v but it was %v", expected, actual) - } -} - -func TestTextMapCarrierGet(t *testing.T) { - tmc := NewTextMapCarrier(map[string]string{key: value}) - tmc.GotN(t, 0) - if got := tmc.Get("empty"); got != "" { - t.Errorf("TextMapCarrier.Get returned %q for an empty key", got) - } - tmc.GotKey(t, "empty") - tmc.GotN(t, 1) - if got := tmc.Get(key); got != value { - t.Errorf("TextMapCarrier.Get(%q) returned %q, want %q", key, got, value) - } - tmc.GotKey(t, key) - tmc.GotN(t, 2) -} - -func TestTextMapCarrierSet(t *testing.T) { - tmc := NewTextMapCarrier(nil) - tmc.SetN(t, 0) - tmc.Set(key, value) - if got, ok := tmc.data[key]; !ok { - t.Errorf("TextMapCarrier.Set(%q,%q) failed to store pair", key, value) - } else if got != value { - t.Errorf("TextMapCarrier.Set(%q,%q) stored (%q,%q), not (%q,%q)", key, value, key, got, key, value) - } - tmc.SetKeyValue(t, key, value) - tmc.SetN(t, 1) -} - -func TestTextMapCarrierReset(t *testing.T) { - tmc := NewTextMapCarrier(map[string]string{key: value}) - tmc.GotN(t, 0) - tmc.SetN(t, 0) - tmc.Reset(nil) - tmc.GotN(t, 0) - tmc.SetN(t, 0) - if got := tmc.Get(key); got != "" { - t.Error("TextMapCarrier.Reset() failed to clear initial data") - } - tmc.GotN(t, 1) - tmc.GotKey(t, key) - tmc.Set(key, value) - tmc.SetKeyValue(t, key, value) - tmc.SetN(t, 1) - tmc.Reset(nil) - tmc.GotN(t, 0) - tmc.SetN(t, 0) - if got := tmc.Get(key); got != "" { - t.Error("TextMapCarrier.Reset() failed to clear data") - } -} diff --git a/sdk/internal/internaltest/text_map_propagator.go b/sdk/internal/internaltest/text_map_propagator.go deleted file mode 100644 index 25dffb0ea..000000000 --- a/sdk/internal/internaltest/text_map_propagator.go +++ /dev/null @@ -1,104 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/text_map_propagator.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package internaltest // import "go.opentelemetry.io/otel/sdk/internal/internaltest" - -import ( - "context" - "fmt" - "strconv" - "strings" - "testing" - - "go.opentelemetry.io/otel/propagation" -) - -type ctxKeyType string - -type state struct { - Injections uint64 - Extractions uint64 -} - -func newState(encoded string) state { - if encoded == "" { - return state{} - } - s0, s1, _ := strings.Cut(encoded, ",") - injects, _ := strconv.ParseUint(s0, 10, 64) - extracts, _ := strconv.ParseUint(s1, 10, 64) - return state{ - Injections: injects, - Extractions: extracts, - } -} - -func (s state) String() string { - return fmt.Sprintf("%d,%d", s.Injections, s.Extractions) -} - -// TextMapPropagator is a propagation.TextMapPropagator used for testing. -type TextMapPropagator struct { - name string - ctxKey ctxKeyType -} - -var _ propagation.TextMapPropagator = (*TextMapPropagator)(nil) - -// NewTextMapPropagator returns a new TextMapPropagator for testing. It will -// use name as the key it injects into a TextMapCarrier when Inject is called. -func NewTextMapPropagator(name string) *TextMapPropagator { - return &TextMapPropagator{name: name, ctxKey: ctxKeyType(name)} -} - -func (p *TextMapPropagator) stateFromContext(ctx context.Context) state { - if v := ctx.Value(p.ctxKey); v != nil { - if s, ok := v.(state); ok { - return s - } - } - return state{} -} - -func (p *TextMapPropagator) stateFromCarrier(carrier propagation.TextMapCarrier) state { - return newState(carrier.Get(p.name)) -} - -// Inject sets cross-cutting concerns for p from ctx into carrier. -func (p *TextMapPropagator) Inject(ctx context.Context, carrier propagation.TextMapCarrier) { - s := p.stateFromContext(ctx) - s.Injections++ - carrier.Set(p.name, s.String()) -} - -// InjectedN tests if p has made n injections to carrier. -func (p *TextMapPropagator) InjectedN(t *testing.T, carrier *TextMapCarrier, n uint64) bool { - if actual := p.stateFromCarrier(carrier).Injections; actual != n { - t.Errorf("TextMapPropagator{%q} injected %d times, not %d", p.name, actual, n) - return false - } - return true -} - -// Extract reads cross-cutting concerns for p from carrier into ctx. -func (p *TextMapPropagator) Extract(ctx context.Context, carrier propagation.TextMapCarrier) context.Context { - s := p.stateFromCarrier(carrier) - s.Extractions++ - return context.WithValue(ctx, p.ctxKey, s) -} - -// ExtractedN tests if p has made n extractions from the lineage of ctx. -// nolint (context is not first arg) -func (p *TextMapPropagator) ExtractedN(t *testing.T, ctx context.Context, n int) bool { - if actual := p.stateFromContext(ctx).Extractions; actual != uint64(n) { - t.Errorf("TextMapPropagator{%q} extracted %d time, not %d", p.name, actual, n) - return false - } - return true -} - -// Fields returns the name of p as the key who's value is set with Inject. -func (p *TextMapPropagator) Fields() []string { return []string{p.name} } diff --git a/sdk/internal/internaltest/text_map_propagator_test.go b/sdk/internal/internaltest/text_map_propagator_test.go deleted file mode 100644 index 67002ec83..000000000 --- a/sdk/internal/internaltest/text_map_propagator_test.go +++ /dev/null @@ -1,61 +0,0 @@ -// Code generated by gotmpl. DO NOT MODIFY. -// source: internal/shared/internaltest/text_map_propagator_test.go.tmpl - -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -package internaltest - -import ( - "context" - "testing" -) - -func TestTextMapPropagatorInjectExtract(t *testing.T) { - name := "testing" - ctx := context.Background() - carrier := NewTextMapCarrier(map[string]string{name: value}) - propagator := NewTextMapPropagator(name) - - propagator.Inject(ctx, carrier) - // Carrier value overridden with state. - if carrier.SetKeyValue(t, name, "1,0") { - // Ensure nothing has been extracted yet. - propagator.ExtractedN(t, ctx, 0) - // Test the injection was counted. - propagator.InjectedN(t, carrier, 1) - } - - ctx = propagator.Extract(ctx, carrier) - v := ctx.Value(ctxKeyType(name)) - if v == nil { - t.Error("TextMapPropagator.Extract failed to extract state") - } - if s, ok := v.(state); !ok { - t.Error("TextMapPropagator.Extract did not extract proper state") - } else if s.Extractions != 1 { - t.Error("TextMapPropagator.Extract did not increment state.Extractions") - } - if carrier.GotKey(t, name) { - // Test the extraction was counted. - propagator.ExtractedN(t, ctx, 1) - // Ensure no additional injection was recorded. - propagator.InjectedN(t, carrier, 1) - } -} - -func TestTextMapPropagatorFields(t *testing.T) { - name := "testing" - propagator := NewTextMapPropagator(name) - if got := propagator.Fields(); len(got) != 1 { - t.Errorf("TextMapPropagator.Fields returned %d fields, want 1", len(got)) - } else if got[0] != name { - t.Errorf("TextMapPropagator.Fields returned %q, want %q", got[0], name) - } -} - -func TestNewStateEmpty(t *testing.T) { - if want, got := (state{}), newState(""); got != want { - t.Errorf("newState(\"\") returned %v, want %v", got, want) - } -}