knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/observability/tracing/provider_test.go (about)

     1  /*
     2  Copyright 2025 The Knative Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package tracing
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"testing"
    23  
    24  	"github.com/google/go-cmp/cmp"
    25  	"knative.dev/pkg/ptr"
    26  )
    27  
    28  func TestNewTrackerProviderProtocols(t *testing.T) {
    29  	cases := []struct {
    30  		name    string
    31  		c       Config
    32  		wantErr bool
    33  	}{{
    34  		name: "grpc",
    35  		c:    Config{Protocol: ProtocolGRPC},
    36  	}, {
    37  		name: "none",
    38  		c:    Config{Protocol: ProtocolNone},
    39  	}, {
    40  		name: "http",
    41  		c:    Config{Protocol: ProtocolHTTPProtobuf},
    42  	}, {
    43  		name:    "bad protocol",
    44  		c:       Config{Protocol: "bad"},
    45  		wantErr: true,
    46  	}, {
    47  		name: "http - bad URL",
    48  		c: Config{
    49  			Protocol: ProtocolHTTPProtobuf,
    50  			Endpoint: "://hello",
    51  		},
    52  		wantErr: true,
    53  	}, {
    54  		name: "http with path in endpoint",
    55  		c: Config{
    56  			Protocol: ProtocolHTTPProtobuf,
    57  			Endpoint: "http://example.com:9090/api/v1/otlp/v1/traces",
    58  		},
    59  	}}
    60  
    61  	for _, tc := range cases {
    62  		t.Run(tc.name, func(t *testing.T) {
    63  			ctx := context.Background()
    64  			_, err := NewTracerProvider(ctx, tc.c)
    65  
    66  			if !tc.wantErr && err != nil {
    67  				t.Error("unexpected failed", err)
    68  			} else if tc.wantErr && err == nil {
    69  				t.Error("expected failure")
    70  			}
    71  		})
    72  	}
    73  }
    74  
    75  func TestEndpointFor(t *testing.T) {
    76  	cases := []string{
    77  		"OTEL_EXPORTER_OTLP_ENDPOINT",
    78  		"OTEL_EXPORTER_OTLP_TRACES_ENDPOINT",
    79  	}
    80  
    81  	optFunc := func(string) *string {
    82  		panic("unexpected call")
    83  	}
    84  
    85  	for _, envKey := range cases {
    86  		t.Run("override "+envKey, func(t *testing.T) {
    87  			t.Setenv(envKey, "https://override.example.com")
    88  
    89  			opt, err := endpointFor(Config{Endpoint: "https://otel.example.com"}, optFunc)
    90  			if err != nil {
    91  				t.Fatal("unexpected error", err)
    92  			}
    93  
    94  			if opt != nil {
    95  				t.Error("expected the option to not be present when 'OTEL_EXPORTER_OTLP_ENDPOINT' is set")
    96  			}
    97  		})
    98  	}
    99  
   100  	t.Run("normal", func(t *testing.T) {
   101  		optFunc := func(string) *string {
   102  			result := "result"
   103  			return &result
   104  		}
   105  		opt, err := endpointFor(Config{Endpoint: "https://otel.example.com"}, optFunc)
   106  		if err != nil {
   107  			t.Fatal("unexpected error", err)
   108  		}
   109  		if *opt != "result" {
   110  			t.Error("expected option to work when no env vars are present")
   111  		}
   112  	})
   113  
   114  	t.Run("missing scheme - defaults to https", func(t *testing.T) {
   115  		optFunc := func(r string) *string {
   116  			return &r
   117  		}
   118  		got, err := endpointFor(Config{Endpoint: "otel.example.com:8080"}, optFunc)
   119  		if err != nil {
   120  			t.Fatal("unexpected err", err)
   121  		}
   122  
   123  		want := ptr.String("https://otel.example.com:8080")
   124  		if diff := cmp.Diff(want, got); diff != "" {
   125  			t.Error("expected option to work when no env vars are present: (-want +got): ", diff)
   126  		}
   127  	})
   128  }
   129  
   130  func TestTracerProviderShutdown(t *testing.T) {
   131  	want := errors.New("some error")
   132  	invoked := false
   133  	shutdown := func(context.Context) error {
   134  		invoked = true
   135  		return want
   136  	}
   137  
   138  	p := TracerProvider{shutdown: shutdown}
   139  	got := p.Shutdown(context.Background())
   140  
   141  	if !invoked {
   142  		t.Fatal("expected shutdown to be invoked")
   143  	}
   144  
   145  	if !errors.Is(got, want) {
   146  		t.Error("unexpected error (-want +got): ", cmp.Diff(want, got))
   147  	}
   148  }
   149  
   150  func TestSampleFor(t *testing.T) {
   151  	cfg := Config{
   152  		SamplingRate: 0.85,
   153  	}
   154  
   155  	cases := []struct {
   156  		name           string
   157  		env            map[string]string
   158  		wantNilSampler bool
   159  		wantErr        bool
   160  	}{{
   161  		name: "sampler override",
   162  		env: map[string]string{
   163  			"OTEL_TRACES_SAMPLER": "some-sampler",
   164  		},
   165  		wantNilSampler: true,
   166  	}, {
   167  		name:           "standard sampler",
   168  		wantNilSampler: false,
   169  	}, {
   170  		name:           "sample arg override",
   171  		wantNilSampler: false,
   172  		env: map[string]string{
   173  			"OTEL_TRACES_SAMPLER_ARG": "1.0",
   174  		},
   175  	}, {
   176  		name:           "sample arg override - bad input",
   177  		wantNilSampler: true,
   178  		wantErr:        true,
   179  		env: map[string]string{
   180  			"OTEL_TRACES_SAMPLER_ARG": "bad-ratio",
   181  		},
   182  	}}
   183  
   184  	for _, tc := range cases {
   185  		t.Run(tc.name, func(t *testing.T) {
   186  			for k, v := range tc.env {
   187  				t.Setenv(k, v)
   188  			}
   189  
   190  			got, err := sampleFor(cfg)
   191  			if tc.wantNilSampler && got != nil {
   192  				t.Error("expected a nil sampler")
   193  			} else if !tc.wantNilSampler && got == nil {
   194  				t.Error("expected a non-nil sampler")
   195  			}
   196  
   197  			if tc.wantErr && err == nil {
   198  				t.Error("expected an error")
   199  			} else if !tc.wantErr && err != nil {
   200  				t.Error("unexpected error")
   201  			}
   202  		})
   203  	}
   204  }