knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/observability/metrics/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 metrics
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/google/go-cmp/cmp"
    25  	"knative.dev/pkg/ptr"
    26  )
    27  
    28  func TestNewMeterProviderProtocols(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: "http - bad URL",
    44  		c: Config{
    45  			Protocol: ProtocolHTTPProtobuf,
    46  			Endpoint: "://hello",
    47  		},
    48  		wantErr: true,
    49  	}, {
    50  		name: "prometheus",
    51  		c:    Config{Protocol: ProtocolPrometheus},
    52  	}, {
    53  		name: "prometheus push with path in endpoint",
    54  		c: Config{
    55  			Protocol: ProtocolHTTPProtobuf,
    56  			Endpoint: "http://example.com:9090/api/v1/otlp/v1/metrics",
    57  		},
    58  	}, {
    59  		name:    "bad protocol",
    60  		c:       Config{Protocol: "bad"},
    61  		wantErr: true,
    62  	}}
    63  
    64  	for _, tc := range cases {
    65  		t.Run(tc.name, func(t *testing.T) {
    66  			ctx := context.Background()
    67  			_, err := NewMeterProvider(ctx, tc.c)
    68  
    69  			if !tc.wantErr && err != nil {
    70  				t.Error("unexpected failed", err)
    71  			} else if tc.wantErr && err == nil {
    72  				t.Error("expected failure")
    73  			}
    74  		})
    75  	}
    76  }
    77  
    78  func TestPrometheusEndpoint(t *testing.T) {
    79  	cases := []struct {
    80  		name    string
    81  		c       Config
    82  		wantErr bool
    83  	}{{
    84  		name: "ipv4",
    85  		c: Config{
    86  			Protocol: ProtocolPrometheus,
    87  			Endpoint: "0.0.0.0:9000", // IPv4 only on port 9000
    88  		},
    89  	}, {
    90  		name: "ipv6",
    91  		c: Config{
    92  			Protocol: ProtocolPrometheus,
    93  			Endpoint: "[::]:9000", // IPv6 only on port 9000
    94  		},
    95  	}, {
    96  		name: "bad endpoint",
    97  		c: Config{
    98  			Protocol: ProtocolPrometheus,
    99  			Endpoint: "[:::9000", // IPv6 only on port 9000
   100  		},
   101  		wantErr: true,
   102  	}}
   103  
   104  	for _, tc := range cases {
   105  		t.Run(tc.name, func(t *testing.T) {
   106  			ctx := context.Background()
   107  			_, err := NewMeterProvider(ctx, tc.c)
   108  
   109  			if !tc.wantErr && err != nil {
   110  				t.Error("unexpected failed", err)
   111  			} else if tc.wantErr && err == nil {
   112  				t.Error("expected failure")
   113  			}
   114  		})
   115  	}
   116  }
   117  
   118  func TestEndpointFor(t *testing.T) {
   119  	cases := []string{
   120  		"OTEL_EXPORTER_OTLP_ENDPOINT",
   121  		"OTEL_EXPORTER_OTLP_METRICS_ENDPOINT",
   122  	}
   123  
   124  	optFunc := func(string) *string {
   125  		panic("unexpected call")
   126  	}
   127  
   128  	for _, envKey := range cases {
   129  		t.Run("override "+envKey, func(t *testing.T) {
   130  			t.Setenv(envKey, "https://override.example.com")
   131  
   132  			opt, err := endpointFor(Config{Endpoint: "https://otel.example.com"}, optFunc)
   133  			if err != nil {
   134  				t.Fatal("unexpected err", err)
   135  			}
   136  
   137  			if opt != nil {
   138  				t.Error("expected the option to not be present when 'OTEL_EXPORTER_OTLP_ENDPOINT' is set")
   139  			}
   140  		})
   141  	}
   142  
   143  	t.Run("normal", func(t *testing.T) {
   144  		optFunc := func(string) *string {
   145  			result := "result"
   146  			return &result
   147  		}
   148  		opt, err := endpointFor(Config{Endpoint: "https://otel.example.com"}, optFunc)
   149  		if err != nil {
   150  			t.Fatal("unexpected err", err)
   151  		}
   152  		if *opt != "result" {
   153  			t.Error("expected option to work when no env vars are present")
   154  		}
   155  	})
   156  
   157  	t.Run("missing scheme - defaults to https", func(t *testing.T) {
   158  		optFunc := func(r string) *string {
   159  			return &r
   160  		}
   161  		got, err := endpointFor(Config{Endpoint: "otel.example.com:8080"}, optFunc)
   162  		if err != nil {
   163  			t.Fatal("unexpected err", err)
   164  		}
   165  
   166  		want := ptr.String("https://otel.example.com:8080")
   167  		if diff := cmp.Diff(want, got); diff != "" {
   168  			t.Error("expected option to work when no env vars are present: (-want +got): ", diff)
   169  		}
   170  	})
   171  }
   172  
   173  func TestIntervalFor(t *testing.T) {
   174  	cases := []string{
   175  		"OTEL_METRIC_EXPORT_INTERVAL",
   176  	}
   177  
   178  	for _, envKey := range cases {
   179  		t.Run("override "+envKey, func(t *testing.T) {
   180  			t.Setenv(envKey, "https://override.example.com")
   181  
   182  			opt := intervalFor(Config{ExportInterval: time.Second})
   183  
   184  			if opt != nil {
   185  				t.Error("expected the option to not be present when 'OTEL_EXPORTER_OTLP_ENDPOINT' is set")
   186  			}
   187  		})
   188  	}
   189  
   190  	t.Run("normal", func(t *testing.T) {
   191  		opt := intervalFor(Config{ExportInterval: time.Second})
   192  
   193  		if opt == nil {
   194  			t.Error("expected the interval option be present when env vars are not set")
   195  		}
   196  	})
   197  }