1// Copyright The OpenTelemetry Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package internal_test
16
17import (
18	"context"
19	"testing"
20
21	octrace "go.opencensus.io/trace"
22
23	"go.opentelemetry.io/otel/bridge/opencensus/internal"
24	"go.opentelemetry.io/otel/bridge/opencensus/internal/oc2otel"
25	"go.opentelemetry.io/otel/bridge/opencensus/internal/otel2oc"
26	"go.opentelemetry.io/otel/trace"
27)
28
29type handler struct{ err error }
30
31func (h *handler) Handle(e error) { h.err = e }
32
33func withHandler() (*handler, func()) {
34	h := new(handler)
35	original := internal.Handle
36	internal.Handle = h.Handle
37	return h, func() { internal.Handle = original }
38}
39
40type tracer struct {
41	ctx  context.Context
42	name string
43	opts []trace.SpanStartOption
44}
45
46func (t *tracer) Start(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
47	t.ctx, t.name, t.opts = ctx, name, opts
48	noop := trace.NewNoopTracerProvider().Tracer("testing")
49	return noop.Start(ctx, name, opts...)
50}
51
52type ctxKey string
53
54func TestTracerStartSpan(t *testing.T) {
55	h, restore := withHandler()
56	defer restore()
57
58	otelTracer := &tracer{}
59	ocTracer := internal.NewTracer(otelTracer)
60
61	ctx := context.WithValue(context.Background(), ctxKey("key"), "value")
62	name := "testing span"
63	ocTracer.StartSpan(ctx, name, octrace.WithSpanKind(octrace.SpanKindClient))
64	if h.err != nil {
65		t.Fatalf("OC tracer.StartSpan errored: %v", h.err)
66	}
67
68	if otelTracer.ctx != ctx {
69		t.Error("OTel tracer.Start called with wrong context")
70	}
71	if otelTracer.name != name {
72		t.Error("OTel tracer.Start called with wrong name")
73	}
74	sk := trace.SpanKindClient
75	c := trace.NewSpanStartConfig(otelTracer.opts...)
76	if c.SpanKind() != sk {
77		t.Errorf("OTel tracer.Start called with wrong options: %#v", c)
78	}
79}
80
81func TestTracerStartSpanReportsErrors(t *testing.T) {
82	h, restore := withHandler()
83	defer restore()
84
85	ocTracer := internal.NewTracer(&tracer{})
86	ocTracer.StartSpan(context.Background(), "", octrace.WithSampler(octrace.AlwaysSample()))
87	if h.err == nil {
88		t.Error("OC tracer.StartSpan no error when converting Sampler")
89	}
90}
91
92func TestTracerStartSpanWithRemoteParent(t *testing.T) {
93	otelTracer := new(tracer)
94	ocTracer := internal.NewTracer(otelTracer)
95	sc := octrace.SpanContext{TraceID: [16]byte{1}, SpanID: [8]byte{1}}
96	converted := oc2otel.SpanContext(sc).WithRemote(true)
97
98	ocTracer.StartSpanWithRemoteParent(context.Background(), "", sc)
99
100	got := trace.SpanContextFromContext(otelTracer.ctx)
101	if !got.Equal(converted) {
102		t.Error("tracer.StartSpanWithRemoteParent failed to set remote parent")
103	}
104}
105
106func TestTracerFromContext(t *testing.T) {
107	sc := trace.NewSpanContext(trace.SpanContextConfig{
108		TraceID: [16]byte{1},
109		SpanID:  [8]byte{1},
110	})
111	ctx := trace.ContextWithSpanContext(context.Background(), sc)
112
113	noop := trace.NewNoopTracerProvider().Tracer("TestTracerFromContext")
114	// Test using the fact that the No-Op span will propagate a span context .
115	ctx, _ = noop.Start(ctx, "test")
116
117	got := internal.NewTracer(noop).FromContext(ctx).SpanContext()
118	// Do not test the convedsion, only that the propagtion.
119	want := otel2oc.SpanContext(sc)
120	if got != want {
121		t.Errorf("tracer.FromContext returned wrong context: %#v", got)
122	}
123}
124
125func TestTracerNewContext(t *testing.T) {
126	sc := trace.NewSpanContext(trace.SpanContextConfig{
127		TraceID: [16]byte{1},
128		SpanID:  [8]byte{1},
129	})
130	ctx := trace.ContextWithSpanContext(context.Background(), sc)
131
132	noop := trace.NewNoopTracerProvider().Tracer("TestTracerNewContext")
133	// Test using the fact that the No-Op span will propagate a span context .
134	_, s := noop.Start(ctx, "test")
135
136	ocTracer := internal.NewTracer(noop)
137	ctx = ocTracer.NewContext(context.Background(), internal.NewSpan(s))
138	got := trace.SpanContextFromContext(ctx)
139
140	if !got.Equal(sc) {
141		t.Error("tracer.NewContext did not attach Span to context")
142	}
143}
144
145type differentSpan struct {
146	octrace.SpanInterface
147}
148
149func (s *differentSpan) String() string { return "testing span" }
150
151func TestTracerNewContextErrors(t *testing.T) {
152	h, restore := withHandler()
153	defer restore()
154
155	ocTracer := internal.NewTracer(&tracer{})
156	ocSpan := octrace.NewSpan(&differentSpan{})
157	ocTracer.NewContext(context.Background(), ocSpan)
158	if h.err == nil {
159		t.Error("tracer.NewContext did not error for unrecognized span")
160	}
161}
162