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 }