154 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
		
		
			
		
	
	
			154 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
|  | // Copyright 2025 The Prometheus Authors
 | ||
|  | // Licensed under the Apache License, Version 2.0 (the "License");
 | ||
|  | // you may not use this file except in compliance with the License.
 | ||
|  | // You may obtain a copy of the License at
 | ||
|  | //
 | ||
|  | // http://www.apache.org/licenses/LICENSE-2.0
 | ||
|  | //
 | ||
|  | // Unless required by applicable law or agreed to in writing, software
 | ||
|  | // distributed under the License is distributed on an "AS IS" BASIS,
 | ||
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | ||
|  | // See the License for the specific language governing permissions and
 | ||
|  | // limitations under the License.
 | ||
|  | 
 | ||
|  | package schema | ||
|  | 
 | ||
|  | import ( | ||
|  | 	"fmt" | ||
|  | 	"testing" | ||
|  | 
 | ||
|  | 	"github.com/prometheus/common/model" | ||
|  | 	"github.com/stretchr/testify/require" | ||
|  | 
 | ||
|  | 	"github.com/prometheus/prometheus/model/labels" | ||
|  | 	"github.com/prometheus/prometheus/util/testutil" | ||
|  | ) | ||
|  | 
 | ||
|  | func TestMetadata(t *testing.T) { | ||
|  | 	testMeta := Metadata{ | ||
|  | 		Name: "metric_total", | ||
|  | 		Type: model.MetricTypeCounter, | ||
|  | 		Unit: "seconds", | ||
|  | 	} | ||
|  | 
 | ||
|  | 	for _, tcase := range []struct { | ||
|  | 		emptyName, emptyType, emptyUnit bool | ||
|  | 	}{ | ||
|  | 		{}, | ||
|  | 		{emptyName: true}, | ||
|  | 		{emptyType: true}, | ||
|  | 		{emptyUnit: true}, | ||
|  | 		{emptyName: true, emptyType: true, emptyUnit: true}, | ||
|  | 	} { | ||
|  | 		var ( | ||
|  | 			expectedMeta   Metadata | ||
|  | 			expectedLabels labels.Labels | ||
|  | 		) | ||
|  | 		{ | ||
|  | 			// Setup expectations.
 | ||
|  | 			lb := labels.NewScratchBuilder(0) | ||
|  | 			lb.Add("foo", "bar") | ||
|  | 
 | ||
|  | 			if !tcase.emptyName { | ||
|  | 				lb.Add(metricName, testMeta.Name) | ||
|  | 				expectedMeta.Name = testMeta.Name | ||
|  | 			} | ||
|  | 			if !tcase.emptyType { | ||
|  | 				lb.Add(metricType, string(testMeta.Type)) | ||
|  | 				expectedMeta.Type = testMeta.Type | ||
|  | 			} else { | ||
|  | 				expectedMeta.Type = model.MetricTypeUnknown | ||
|  | 			} | ||
|  | 			if !tcase.emptyUnit { | ||
|  | 				lb.Add(metricUnit, testMeta.Unit) | ||
|  | 				expectedMeta.Unit = testMeta.Unit | ||
|  | 			} | ||
|  | 			lb.Sort() | ||
|  | 			expectedLabels = lb.Labels() | ||
|  | 		} | ||
|  | 
 | ||
|  | 		t.Run(fmt.Sprintf("meta=%#v", expectedMeta), func(t *testing.T) { | ||
|  | 			{ | ||
|  | 				// From labels to Metadata.
 | ||
|  | 				got := NewMetadataFromLabels(expectedLabels) | ||
|  | 				require.Equal(t, expectedMeta, got) | ||
|  | 			} | ||
|  | 			{ | ||
|  | 				// Empty methods.
 | ||
|  | 				require.Equal(t, tcase.emptyName, expectedMeta.IsEmptyFor(metricName)) | ||
|  | 				require.Equal(t, tcase.emptyType, expectedMeta.IsEmptyFor(metricType)) | ||
|  | 				require.Equal(t, tcase.emptyType, expectedMeta.IsTypeEmpty()) | ||
|  | 				require.Equal(t, tcase.emptyUnit, expectedMeta.IsEmptyFor(metricUnit)) | ||
|  | 			} | ||
|  | 			{ | ||
|  | 				// From Metadata to labels for various builders.
 | ||
|  | 				slb := labels.NewScratchBuilder(0) | ||
|  | 				slb.Add("foo", "bar") | ||
|  | 				expectedMeta.AddToLabels(&slb) | ||
|  | 				slb.Sort() | ||
|  | 				testutil.RequireEqual(t, expectedLabels, slb.Labels()) | ||
|  | 
 | ||
|  | 				lb := labels.NewBuilder(labels.FromStrings("foo", "bar")) | ||
|  | 				expectedMeta.SetToLabels(lb) | ||
|  | 				testutil.RequireEqual(t, expectedLabels, lb.Labels()) | ||
|  | 			} | ||
|  | 		}) | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | func TestIgnoreOverriddenMetadataLabelsScratchBuilder(t *testing.T) { | ||
|  | 	// PROM-39 specifies that metadata labels should be sourced primarily from the metadata structures.
 | ||
|  | 	// However, the original labels should be preserved IF the metadata structure does not set or support certain information.
 | ||
|  | 	// Test those cases with common label interactions.
 | ||
|  | 	incomingLabels := labels.FromStrings(metricName, "different_name", metricType, string(model.MetricTypeSummary), metricUnit, "MB", "foo", "bar") | ||
|  | 	for _, tcase := range []struct { | ||
|  | 		highPrioMeta   Metadata | ||
|  | 		expectedLabels labels.Labels | ||
|  | 	}{ | ||
|  | 		{ | ||
|  | 			expectedLabels: incomingLabels, | ||
|  | 		}, | ||
|  | 		{ | ||
|  | 			highPrioMeta: Metadata{ | ||
|  | 				Name: "metric_total", | ||
|  | 				Type: model.MetricTypeCounter, | ||
|  | 				Unit: "seconds", | ||
|  | 			}, | ||
|  | 			expectedLabels: labels.FromStrings(metricName, "metric_total", metricType, string(model.MetricTypeCounter), metricUnit, "seconds", "foo", "bar"), | ||
|  | 		}, | ||
|  | 		{ | ||
|  | 			highPrioMeta: Metadata{ | ||
|  | 				Name: "metric_total", | ||
|  | 				Type: model.MetricTypeCounter, | ||
|  | 			}, | ||
|  | 			expectedLabels: labels.FromStrings(metricName, "metric_total", metricType, string(model.MetricTypeCounter), metricUnit, "MB", "foo", "bar"), | ||
|  | 		}, | ||
|  | 		{ | ||
|  | 			highPrioMeta: Metadata{ | ||
|  | 				Type: model.MetricTypeCounter, | ||
|  | 				Unit: "seconds", | ||
|  | 			}, | ||
|  | 			expectedLabels: labels.FromStrings(metricName, "different_name", metricType, string(model.MetricTypeCounter), metricUnit, "seconds", "foo", "bar"), | ||
|  | 		}, | ||
|  | 		{ | ||
|  | 			highPrioMeta: Metadata{ | ||
|  | 				Name: "metric_total", | ||
|  | 				Type: model.MetricTypeUnknown, | ||
|  | 				Unit: "seconds", | ||
|  | 			}, | ||
|  | 			expectedLabels: labels.FromStrings(metricName, "metric_total", metricType, string(model.MetricTypeSummary), metricUnit, "seconds", "foo", "bar"), | ||
|  | 		}, | ||
|  | 	} { | ||
|  | 		t.Run(fmt.Sprintf("meta=%#v", tcase.highPrioMeta), func(t *testing.T) { | ||
|  | 			lb := labels.NewScratchBuilder(0) | ||
|  | 			tcase.highPrioMeta.AddToLabels(&lb) | ||
|  | 			wrapped := &IgnoreOverriddenMetadataLabelsScratchBuilder{ScratchBuilder: &lb, Overwrite: tcase.highPrioMeta} | ||
|  | 			incomingLabels.Range(func(l labels.Label) { | ||
|  | 				wrapped.Add(l.Name, l.Value) | ||
|  | 			}) | ||
|  | 			lb.Sort() | ||
|  | 			require.Equal(t, tcase.expectedLabels, lb.Labels()) | ||
|  | 		}) | ||
|  | 	} | ||
|  | } |