mirror of
				https://github.com/coredns/coredns.git
				synced 2025-10-31 02:03:20 -04:00 
			
		
		
		
	Dep helper (#2151)
* Add dep task to update go dependencies * Update go dependencies
This commit is contained in:
		
				
					committed by
					
						 Miek Gieben
						Miek Gieben
					
				
			
			
				
	
			
			
			
						parent
						
							8f8b81f56b
						
					
				
				
					commit
					0e8977761d
				
			
							
								
								
									
										167
									
								
								vendor/github.com/prometheus/common/expfmt/bench_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										167
									
								
								vendor/github.com/prometheus/common/expfmt/bench_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,167 +0,0 @@ | ||||
| // Copyright 2015 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 expfmt | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"compress/gzip" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/matttproud/golang_protobuf_extensions/pbutil" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
| ) | ||||
|  | ||||
| var parser TextParser | ||||
|  | ||||
| // Benchmarks to show how much penalty text format parsing actually inflicts. | ||||
| // | ||||
| // Example results on Linux 3.13.0, Intel(R) Core(TM) i7-4700MQ CPU @ 2.40GHz, go1.4. | ||||
| // | ||||
| // BenchmarkParseText          1000           1188535 ns/op          205085 B/op       6135 allocs/op | ||||
| // BenchmarkParseTextGzip      1000           1376567 ns/op          246224 B/op       6151 allocs/op | ||||
| // BenchmarkParseProto        10000            172790 ns/op           52258 B/op       1160 allocs/op | ||||
| // BenchmarkParseProtoGzip     5000            324021 ns/op           94931 B/op       1211 allocs/op | ||||
| // BenchmarkParseProtoMap     10000            187946 ns/op           58714 B/op       1203 allocs/op | ||||
| // | ||||
| // CONCLUSION: The overhead for the map is negligible. Text format needs ~5x more allocations. | ||||
| // Without compression, it needs ~7x longer, but with compression (the more relevant scenario), | ||||
| // the difference becomes less relevant, only ~4x. | ||||
| // | ||||
| // The test data contains 248 samples. | ||||
|  | ||||
| // BenchmarkParseText benchmarks the parsing of a text-format scrape into metric | ||||
| // family DTOs. | ||||
| func BenchmarkParseText(b *testing.B) { | ||||
| 	b.StopTimer() | ||||
| 	data, err := ioutil.ReadFile("testdata/text") | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
| 	b.StartTimer() | ||||
|  | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		if _, err := parser.TextToMetricFamilies(bytes.NewReader(data)); err != nil { | ||||
| 			b.Fatal(err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // BenchmarkParseTextGzip benchmarks the parsing of a gzipped text-format scrape | ||||
| // into metric family DTOs. | ||||
| func BenchmarkParseTextGzip(b *testing.B) { | ||||
| 	b.StopTimer() | ||||
| 	data, err := ioutil.ReadFile("testdata/text.gz") | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
| 	b.StartTimer() | ||||
|  | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		in, err := gzip.NewReader(bytes.NewReader(data)) | ||||
| 		if err != nil { | ||||
| 			b.Fatal(err) | ||||
| 		} | ||||
| 		if _, err := parser.TextToMetricFamilies(in); err != nil { | ||||
| 			b.Fatal(err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // BenchmarkParseProto benchmarks the parsing of a protobuf-format scrape into | ||||
| // metric family DTOs. Note that this does not build a map of metric families | ||||
| // (as the text version does), because it is not required for Prometheus | ||||
| // ingestion either. (However, it is required for the text-format parsing, as | ||||
| // the metric family might be sprinkled all over the text, while the | ||||
| // protobuf-format guarantees bundling at one place.) | ||||
| func BenchmarkParseProto(b *testing.B) { | ||||
| 	b.StopTimer() | ||||
| 	data, err := ioutil.ReadFile("testdata/protobuf") | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
| 	b.StartTimer() | ||||
|  | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		family := &dto.MetricFamily{} | ||||
| 		in := bytes.NewReader(data) | ||||
| 		for { | ||||
| 			family.Reset() | ||||
| 			if _, err := pbutil.ReadDelimited(in, family); err != nil { | ||||
| 				if err == io.EOF { | ||||
| 					break | ||||
| 				} | ||||
| 				b.Fatal(err) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // BenchmarkParseProtoGzip is like BenchmarkParseProto above, but parses gzipped | ||||
| // protobuf format. | ||||
| func BenchmarkParseProtoGzip(b *testing.B) { | ||||
| 	b.StopTimer() | ||||
| 	data, err := ioutil.ReadFile("testdata/protobuf.gz") | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
| 	b.StartTimer() | ||||
|  | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		family := &dto.MetricFamily{} | ||||
| 		in, err := gzip.NewReader(bytes.NewReader(data)) | ||||
| 		if err != nil { | ||||
| 			b.Fatal(err) | ||||
| 		} | ||||
| 		for { | ||||
| 			family.Reset() | ||||
| 			if _, err := pbutil.ReadDelimited(in, family); err != nil { | ||||
| 				if err == io.EOF { | ||||
| 					break | ||||
| 				} | ||||
| 				b.Fatal(err) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // BenchmarkParseProtoMap is like BenchmarkParseProto but DOES put the parsed | ||||
| // metric family DTOs into a map. This is not happening during Prometheus | ||||
| // ingestion. It is just here to measure the overhead of that map creation and | ||||
| // separate it from the overhead of the text format parsing. | ||||
| func BenchmarkParseProtoMap(b *testing.B) { | ||||
| 	b.StopTimer() | ||||
| 	data, err := ioutil.ReadFile("testdata/protobuf") | ||||
| 	if err != nil { | ||||
| 		b.Fatal(err) | ||||
| 	} | ||||
| 	b.StartTimer() | ||||
|  | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		families := map[string]*dto.MetricFamily{} | ||||
| 		in := bytes.NewReader(data) | ||||
| 		for { | ||||
| 			family := &dto.MetricFamily{} | ||||
| 			if _, err := pbutil.ReadDelimited(in, family); err != nil { | ||||
| 				if err == io.EOF { | ||||
| 					break | ||||
| 				} | ||||
| 				b.Fatal(err) | ||||
| 			} | ||||
| 			families[family.GetName()] = family | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										435
									
								
								vendor/github.com/prometheus/common/expfmt/decode_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										435
									
								
								vendor/github.com/prometheus/common/expfmt/decode_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,435 +0,0 @@ | ||||
| // Copyright 2015 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 expfmt | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"reflect" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
|  | ||||
| 	"github.com/prometheus/common/model" | ||||
| ) | ||||
|  | ||||
| func TestTextDecoder(t *testing.T) { | ||||
| 	var ( | ||||
| 		ts = model.Now() | ||||
| 		in = ` | ||||
| # Only a quite simple scenario with two metric families. | ||||
| # More complicated tests of the parser itself can be found in the text package. | ||||
| # TYPE mf2 counter | ||||
| mf2 3 | ||||
| mf1{label="value1"} -3.14 123456 | ||||
| mf1{label="value2"} 42 | ||||
| mf2 4 | ||||
| ` | ||||
| 		out = model.Vector{ | ||||
| 			&model.Sample{ | ||||
| 				Metric: model.Metric{ | ||||
| 					model.MetricNameLabel: "mf1", | ||||
| 					"label":               "value1", | ||||
| 				}, | ||||
| 				Value:     -3.14, | ||||
| 				Timestamp: 123456, | ||||
| 			}, | ||||
| 			&model.Sample{ | ||||
| 				Metric: model.Metric{ | ||||
| 					model.MetricNameLabel: "mf1", | ||||
| 					"label":               "value2", | ||||
| 				}, | ||||
| 				Value:     42, | ||||
| 				Timestamp: ts, | ||||
| 			}, | ||||
| 			&model.Sample{ | ||||
| 				Metric: model.Metric{ | ||||
| 					model.MetricNameLabel: "mf2", | ||||
| 				}, | ||||
| 				Value:     3, | ||||
| 				Timestamp: ts, | ||||
| 			}, | ||||
| 			&model.Sample{ | ||||
| 				Metric: model.Metric{ | ||||
| 					model.MetricNameLabel: "mf2", | ||||
| 				}, | ||||
| 				Value:     4, | ||||
| 				Timestamp: ts, | ||||
| 			}, | ||||
| 		} | ||||
| 	) | ||||
|  | ||||
| 	dec := &SampleDecoder{ | ||||
| 		Dec: &textDecoder{r: strings.NewReader(in)}, | ||||
| 		Opts: &DecodeOptions{ | ||||
| 			Timestamp: ts, | ||||
| 		}, | ||||
| 	} | ||||
| 	var all model.Vector | ||||
| 	for { | ||||
| 		var smpls model.Vector | ||||
| 		err := dec.Decode(&smpls) | ||||
| 		if err == io.EOF { | ||||
| 			break | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			t.Fatal(err) | ||||
| 		} | ||||
| 		all = append(all, smpls...) | ||||
| 	} | ||||
| 	sort.Sort(all) | ||||
| 	sort.Sort(out) | ||||
| 	if !reflect.DeepEqual(all, out) { | ||||
| 		t.Fatalf("output does not match") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestProtoDecoder(t *testing.T) { | ||||
|  | ||||
| 	var testTime = model.Now() | ||||
|  | ||||
| 	scenarios := []struct { | ||||
| 		in       string | ||||
| 		expected model.Vector | ||||
| 		fail     bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			in: "", | ||||
| 		}, | ||||
| 		{ | ||||
| 			in:   "\x8f\x01\n\rrequest_count\x12\x12Number of requests\x18\x00\"0\n#\n\x0fsome_!abel_name\x12\x10some_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00E\xc0\"6\n)\n\x12another_label_name\x12\x13another_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00U@", | ||||
| 			fail: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in: "\x8f\x01\n\rrequest_count\x12\x12Number of requests\x18\x00\"0\n#\n\x0fsome_label_name\x12\x10some_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00E\xc0\"6\n)\n\x12another_label_name\x12\x13another_label_value\x1a\t\t\x00\x00\x00\x00\x00\x00U@", | ||||
| 			expected: model.Vector{ | ||||
| 				&model.Sample{ | ||||
| 					Metric: model.Metric{ | ||||
| 						model.MetricNameLabel: "request_count", | ||||
| 						"some_label_name":     "some_label_value", | ||||
| 					}, | ||||
| 					Value:     -42, | ||||
| 					Timestamp: testTime, | ||||
| 				}, | ||||
| 				&model.Sample{ | ||||
| 					Metric: model.Metric{ | ||||
| 						model.MetricNameLabel: "request_count", | ||||
| 						"another_label_name":  "another_label_value", | ||||
| 					}, | ||||
| 					Value:     84, | ||||
| 					Timestamp: testTime, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in: "\xb9\x01\n\rrequest_count\x12\x12Number of requests\x18\x02\"O\n#\n\x0fsome_label_name\x12\x10some_label_value\"(\x1a\x12\t\xaeG\xe1z\x14\xae\xef?\x11\x00\x00\x00\x00\x00\x00E\xc0\x1a\x12\t+\x87\x16\xd9\xce\xf7\xef?\x11\x00\x00\x00\x00\x00\x00U\xc0\"A\n)\n\x12another_label_name\x12\x13another_label_value\"\x14\x1a\x12\t\x00\x00\x00\x00\x00\x00\xe0?\x11\x00\x00\x00\x00\x00\x00$@", | ||||
| 			expected: model.Vector{ | ||||
| 				&model.Sample{ | ||||
| 					Metric: model.Metric{ | ||||
| 						model.MetricNameLabel: "request_count_count", | ||||
| 						"some_label_name":     "some_label_value", | ||||
| 					}, | ||||
| 					Value:     0, | ||||
| 					Timestamp: testTime, | ||||
| 				}, | ||||
| 				&model.Sample{ | ||||
| 					Metric: model.Metric{ | ||||
| 						model.MetricNameLabel: "request_count_sum", | ||||
| 						"some_label_name":     "some_label_value", | ||||
| 					}, | ||||
| 					Value:     0, | ||||
| 					Timestamp: testTime, | ||||
| 				}, | ||||
| 				&model.Sample{ | ||||
| 					Metric: model.Metric{ | ||||
| 						model.MetricNameLabel: "request_count", | ||||
| 						"some_label_name":     "some_label_value", | ||||
| 						"quantile":            "0.99", | ||||
| 					}, | ||||
| 					Value:     -42, | ||||
| 					Timestamp: testTime, | ||||
| 				}, | ||||
| 				&model.Sample{ | ||||
| 					Metric: model.Metric{ | ||||
| 						model.MetricNameLabel: "request_count", | ||||
| 						"some_label_name":     "some_label_value", | ||||
| 						"quantile":            "0.999", | ||||
| 					}, | ||||
| 					Value:     -84, | ||||
| 					Timestamp: testTime, | ||||
| 				}, | ||||
| 				&model.Sample{ | ||||
| 					Metric: model.Metric{ | ||||
| 						model.MetricNameLabel: "request_count_count", | ||||
| 						"another_label_name":  "another_label_value", | ||||
| 					}, | ||||
| 					Value:     0, | ||||
| 					Timestamp: testTime, | ||||
| 				}, | ||||
| 				&model.Sample{ | ||||
| 					Metric: model.Metric{ | ||||
| 						model.MetricNameLabel: "request_count_sum", | ||||
| 						"another_label_name":  "another_label_value", | ||||
| 					}, | ||||
| 					Value:     0, | ||||
| 					Timestamp: testTime, | ||||
| 				}, | ||||
| 				&model.Sample{ | ||||
| 					Metric: model.Metric{ | ||||
| 						model.MetricNameLabel: "request_count", | ||||
| 						"another_label_name":  "another_label_value", | ||||
| 						"quantile":            "0.5", | ||||
| 					}, | ||||
| 					Value:     10, | ||||
| 					Timestamp: testTime, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in: "\x8d\x01\n\x1drequest_duration_microseconds\x12\x15The response latency.\x18\x04\"S:Q\b\x85\x15\x11\xcd\xcc\xccL\x8f\xcb:A\x1a\v\b{\x11\x00\x00\x00\x00\x00\x00Y@\x1a\f\b\x9c\x03\x11\x00\x00\x00\x00\x00\x00^@\x1a\f\b\xd0\x04\x11\x00\x00\x00\x00\x00\x00b@\x1a\f\b\xf4\v\x11\x9a\x99\x99\x99\x99\x99e@\x1a\f\b\x85\x15\x11\x00\x00\x00\x00\x00\x00\xf0\u007f", | ||||
| 			expected: model.Vector{ | ||||
| 				&model.Sample{ | ||||
| 					Metric: model.Metric{ | ||||
| 						model.MetricNameLabel: "request_duration_microseconds_bucket", | ||||
| 						"le": "100", | ||||
| 					}, | ||||
| 					Value:     123, | ||||
| 					Timestamp: testTime, | ||||
| 				}, | ||||
| 				&model.Sample{ | ||||
| 					Metric: model.Metric{ | ||||
| 						model.MetricNameLabel: "request_duration_microseconds_bucket", | ||||
| 						"le": "120", | ||||
| 					}, | ||||
| 					Value:     412, | ||||
| 					Timestamp: testTime, | ||||
| 				}, | ||||
| 				&model.Sample{ | ||||
| 					Metric: model.Metric{ | ||||
| 						model.MetricNameLabel: "request_duration_microseconds_bucket", | ||||
| 						"le": "144", | ||||
| 					}, | ||||
| 					Value:     592, | ||||
| 					Timestamp: testTime, | ||||
| 				}, | ||||
| 				&model.Sample{ | ||||
| 					Metric: model.Metric{ | ||||
| 						model.MetricNameLabel: "request_duration_microseconds_bucket", | ||||
| 						"le": "172.8", | ||||
| 					}, | ||||
| 					Value:     1524, | ||||
| 					Timestamp: testTime, | ||||
| 				}, | ||||
| 				&model.Sample{ | ||||
| 					Metric: model.Metric{ | ||||
| 						model.MetricNameLabel: "request_duration_microseconds_bucket", | ||||
| 						"le": "+Inf", | ||||
| 					}, | ||||
| 					Value:     2693, | ||||
| 					Timestamp: testTime, | ||||
| 				}, | ||||
| 				&model.Sample{ | ||||
| 					Metric: model.Metric{ | ||||
| 						model.MetricNameLabel: "request_duration_microseconds_sum", | ||||
| 					}, | ||||
| 					Value:     1756047.3, | ||||
| 					Timestamp: testTime, | ||||
| 				}, | ||||
| 				&model.Sample{ | ||||
| 					Metric: model.Metric{ | ||||
| 						model.MetricNameLabel: "request_duration_microseconds_count", | ||||
| 					}, | ||||
| 					Value:     2693, | ||||
| 					Timestamp: testTime, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			// The metric type is unset in this protobuf, which needs to be handled | ||||
| 			// correctly by the decoder. | ||||
| 			in: "\x1c\n\rrequest_count\"\v\x1a\t\t\x00\x00\x00\x00\x00\x00\xf0?", | ||||
| 			expected: model.Vector{ | ||||
| 				&model.Sample{ | ||||
| 					Metric: model.Metric{ | ||||
| 						model.MetricNameLabel: "request_count", | ||||
| 					}, | ||||
| 					Value:     1, | ||||
| 					Timestamp: testTime, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, scenario := range scenarios { | ||||
| 		dec := &SampleDecoder{ | ||||
| 			Dec: &protoDecoder{r: strings.NewReader(scenario.in)}, | ||||
| 			Opts: &DecodeOptions{ | ||||
| 				Timestamp: testTime, | ||||
| 			}, | ||||
| 		} | ||||
|  | ||||
| 		var all model.Vector | ||||
| 		for { | ||||
| 			var smpls model.Vector | ||||
| 			err := dec.Decode(&smpls) | ||||
| 			if err == io.EOF { | ||||
| 				break | ||||
| 			} | ||||
| 			if scenario.fail { | ||||
| 				if err == nil { | ||||
| 					t.Fatal("Expected error but got none") | ||||
| 				} | ||||
| 				break | ||||
| 			} | ||||
| 			if err != nil { | ||||
| 				t.Fatal(err) | ||||
| 			} | ||||
| 			all = append(all, smpls...) | ||||
| 		} | ||||
| 		sort.Sort(all) | ||||
| 		sort.Sort(scenario.expected) | ||||
| 		if !reflect.DeepEqual(all, scenario.expected) { | ||||
| 			t.Fatalf("%d. output does not match, want: %#v, got %#v", i, scenario.expected, all) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func testDiscriminatorHTTPHeader(t testing.TB) { | ||||
| 	var scenarios = []struct { | ||||
| 		input  map[string]string | ||||
| 		output Format | ||||
| 		err    error | ||||
| 	}{ | ||||
| 		{ | ||||
| 			input:  map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="delimited"`}, | ||||
| 			output: FmtProtoDelim, | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:  map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="illegal"; encoding="delimited"`}, | ||||
| 			output: FmtUnknown, | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:  map[string]string{"Content-Type": `application/vnd.google.protobuf; proto="io.prometheus.client.MetricFamily"; encoding="illegal"`}, | ||||
| 			output: FmtUnknown, | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:  map[string]string{"Content-Type": `text/plain; version=0.0.4`}, | ||||
| 			output: FmtText, | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:  map[string]string{"Content-Type": `text/plain`}, | ||||
| 			output: FmtText, | ||||
| 		}, | ||||
| 		{ | ||||
| 			input:  map[string]string{"Content-Type": `text/plain; version=0.0.3`}, | ||||
| 			output: FmtUnknown, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, scenario := range scenarios { | ||||
| 		var header http.Header | ||||
|  | ||||
| 		if len(scenario.input) > 0 { | ||||
| 			header = http.Header{} | ||||
| 		} | ||||
|  | ||||
| 		for key, value := range scenario.input { | ||||
| 			header.Add(key, value) | ||||
| 		} | ||||
|  | ||||
| 		actual := ResponseFormat(header) | ||||
|  | ||||
| 		if scenario.output != actual { | ||||
| 			t.Errorf("%d. expected %s, got %s", i, scenario.output, actual) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestDiscriminatorHTTPHeader(t *testing.T) { | ||||
| 	testDiscriminatorHTTPHeader(t) | ||||
| } | ||||
|  | ||||
| func BenchmarkDiscriminatorHTTPHeader(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		testDiscriminatorHTTPHeader(b) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestExtractSamples(t *testing.T) { | ||||
| 	var ( | ||||
| 		goodMetricFamily1 = &dto.MetricFamily{ | ||||
| 			Name: proto.String("foo"), | ||||
| 			Help: proto.String("Help for foo."), | ||||
| 			Type: dto.MetricType_COUNTER.Enum(), | ||||
| 			Metric: []*dto.Metric{ | ||||
| 				&dto.Metric{ | ||||
| 					Counter: &dto.Counter{ | ||||
| 						Value: proto.Float64(4711), | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		goodMetricFamily2 = &dto.MetricFamily{ | ||||
| 			Name: proto.String("bar"), | ||||
| 			Help: proto.String("Help for bar."), | ||||
| 			Type: dto.MetricType_GAUGE.Enum(), | ||||
| 			Metric: []*dto.Metric{ | ||||
| 				&dto.Metric{ | ||||
| 					Gauge: &dto.Gauge{ | ||||
| 						Value: proto.Float64(3.14), | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 		badMetricFamily = &dto.MetricFamily{ | ||||
| 			Name: proto.String("bad"), | ||||
| 			Help: proto.String("Help for bad."), | ||||
| 			Type: dto.MetricType(42).Enum(), | ||||
| 			Metric: []*dto.Metric{ | ||||
| 				&dto.Metric{ | ||||
| 					Gauge: &dto.Gauge{ | ||||
| 						Value: proto.Float64(2.7), | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
|  | ||||
| 		opts = &DecodeOptions{ | ||||
| 			Timestamp: 42, | ||||
| 		} | ||||
| 	) | ||||
|  | ||||
| 	got, err := ExtractSamples(opts, goodMetricFamily1, goodMetricFamily2) | ||||
| 	if err != nil { | ||||
| 		t.Error("Unexpected error from ExtractSamples:", err) | ||||
| 	} | ||||
| 	want := model.Vector{ | ||||
| 		&model.Sample{Metric: model.Metric{model.MetricNameLabel: "foo"}, Value: 4711, Timestamp: 42}, | ||||
| 		&model.Sample{Metric: model.Metric{model.MetricNameLabel: "bar"}, Value: 3.14, Timestamp: 42}, | ||||
| 	} | ||||
| 	if !reflect.DeepEqual(got, want) { | ||||
| 		t.Errorf("unexpected samples extracted, got: %v, want: %v", got, want) | ||||
| 	} | ||||
|  | ||||
| 	got, err = ExtractSamples(opts, goodMetricFamily1, badMetricFamily, goodMetricFamily2) | ||||
| 	if err == nil { | ||||
| 		t.Error("Expected error from ExtractSamples") | ||||
| 	} | ||||
| 	if !reflect.DeepEqual(got, want) { | ||||
| 		t.Errorf("unexpected samples extracted, got: %v, want: %v", got, want) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										443
									
								
								vendor/github.com/prometheus/common/expfmt/text_create_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										443
									
								
								vendor/github.com/prometheus/common/expfmt/text_create_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,443 +0,0 @@ | ||||
| // Copyright 2014 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 expfmt | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"math" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/golang/protobuf/proto" | ||||
|  | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
| ) | ||||
|  | ||||
| func testCreate(t testing.TB) { | ||||
| 	var scenarios = []struct { | ||||
| 		in  *dto.MetricFamily | ||||
| 		out string | ||||
| 	}{ | ||||
| 		// 0: Counter, NaN as value, timestamp given. | ||||
| 		{ | ||||
| 			in: &dto.MetricFamily{ | ||||
| 				Name: proto.String("name"), | ||||
| 				Help: proto.String("two-line\n doc  str\\ing"), | ||||
| 				Type: dto.MetricType_COUNTER.Enum(), | ||||
| 				Metric: []*dto.Metric{ | ||||
| 					&dto.Metric{ | ||||
| 						Label: []*dto.LabelPair{ | ||||
| 							&dto.LabelPair{ | ||||
| 								Name:  proto.String("labelname"), | ||||
| 								Value: proto.String("val1"), | ||||
| 							}, | ||||
| 							&dto.LabelPair{ | ||||
| 								Name:  proto.String("basename"), | ||||
| 								Value: proto.String("basevalue"), | ||||
| 							}, | ||||
| 						}, | ||||
| 						Counter: &dto.Counter{ | ||||
| 							Value: proto.Float64(math.NaN()), | ||||
| 						}, | ||||
| 					}, | ||||
| 					&dto.Metric{ | ||||
| 						Label: []*dto.LabelPair{ | ||||
| 							&dto.LabelPair{ | ||||
| 								Name:  proto.String("labelname"), | ||||
| 								Value: proto.String("val2"), | ||||
| 							}, | ||||
| 							&dto.LabelPair{ | ||||
| 								Name:  proto.String("basename"), | ||||
| 								Value: proto.String("basevalue"), | ||||
| 							}, | ||||
| 						}, | ||||
| 						Counter: &dto.Counter{ | ||||
| 							Value: proto.Float64(.23), | ||||
| 						}, | ||||
| 						TimestampMs: proto.Int64(1234567890), | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			out: `# HELP name two-line\n doc  str\\ing | ||||
| # TYPE name counter | ||||
| name{labelname="val1",basename="basevalue"} NaN | ||||
| name{labelname="val2",basename="basevalue"} 0.23 1234567890 | ||||
| `, | ||||
| 		}, | ||||
| 		// 1: Gauge, some escaping required, +Inf as value, multi-byte characters in label values. | ||||
| 		{ | ||||
| 			in: &dto.MetricFamily{ | ||||
| 				Name: proto.String("gauge_name"), | ||||
| 				Help: proto.String("gauge\ndoc\nstr\"ing"), | ||||
| 				Type: dto.MetricType_GAUGE.Enum(), | ||||
| 				Metric: []*dto.Metric{ | ||||
| 					&dto.Metric{ | ||||
| 						Label: []*dto.LabelPair{ | ||||
| 							&dto.LabelPair{ | ||||
| 								Name:  proto.String("name_1"), | ||||
| 								Value: proto.String("val with\nnew line"), | ||||
| 							}, | ||||
| 							&dto.LabelPair{ | ||||
| 								Name:  proto.String("name_2"), | ||||
| 								Value: proto.String("val with \\backslash and \"quotes\""), | ||||
| 							}, | ||||
| 						}, | ||||
| 						Gauge: &dto.Gauge{ | ||||
| 							Value: proto.Float64(math.Inf(+1)), | ||||
| 						}, | ||||
| 					}, | ||||
| 					&dto.Metric{ | ||||
| 						Label: []*dto.LabelPair{ | ||||
| 							&dto.LabelPair{ | ||||
| 								Name:  proto.String("name_1"), | ||||
| 								Value: proto.String("Björn"), | ||||
| 							}, | ||||
| 							&dto.LabelPair{ | ||||
| 								Name:  proto.String("name_2"), | ||||
| 								Value: proto.String("佖佥"), | ||||
| 							}, | ||||
| 						}, | ||||
| 						Gauge: &dto.Gauge{ | ||||
| 							Value: proto.Float64(3.14E42), | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			out: `# HELP gauge_name gauge\ndoc\nstr"ing | ||||
| # TYPE gauge_name gauge | ||||
| gauge_name{name_1="val with\nnew line",name_2="val with \\backslash and \"quotes\""} +Inf | ||||
| gauge_name{name_1="Björn",name_2="佖佥"} 3.14e+42 | ||||
| `, | ||||
| 		}, | ||||
| 		// 2: Untyped, no help, one sample with no labels and -Inf as value, another sample with one label. | ||||
| 		{ | ||||
| 			in: &dto.MetricFamily{ | ||||
| 				Name: proto.String("untyped_name"), | ||||
| 				Type: dto.MetricType_UNTYPED.Enum(), | ||||
| 				Metric: []*dto.Metric{ | ||||
| 					&dto.Metric{ | ||||
| 						Untyped: &dto.Untyped{ | ||||
| 							Value: proto.Float64(math.Inf(-1)), | ||||
| 						}, | ||||
| 					}, | ||||
| 					&dto.Metric{ | ||||
| 						Label: []*dto.LabelPair{ | ||||
| 							&dto.LabelPair{ | ||||
| 								Name:  proto.String("name_1"), | ||||
| 								Value: proto.String("value 1"), | ||||
| 							}, | ||||
| 						}, | ||||
| 						Untyped: &dto.Untyped{ | ||||
| 							Value: proto.Float64(-1.23e-45), | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			out: `# TYPE untyped_name untyped | ||||
| untyped_name -Inf | ||||
| untyped_name{name_1="value 1"} -1.23e-45 | ||||
| `, | ||||
| 		}, | ||||
| 		// 3: Summary. | ||||
| 		{ | ||||
| 			in: &dto.MetricFamily{ | ||||
| 				Name: proto.String("summary_name"), | ||||
| 				Help: proto.String("summary docstring"), | ||||
| 				Type: dto.MetricType_SUMMARY.Enum(), | ||||
| 				Metric: []*dto.Metric{ | ||||
| 					&dto.Metric{ | ||||
| 						Summary: &dto.Summary{ | ||||
| 							SampleCount: proto.Uint64(42), | ||||
| 							SampleSum:   proto.Float64(-3.4567), | ||||
| 							Quantile: []*dto.Quantile{ | ||||
| 								&dto.Quantile{ | ||||
| 									Quantile: proto.Float64(0.5), | ||||
| 									Value:    proto.Float64(-1.23), | ||||
| 								}, | ||||
| 								&dto.Quantile{ | ||||
| 									Quantile: proto.Float64(0.9), | ||||
| 									Value:    proto.Float64(.2342354), | ||||
| 								}, | ||||
| 								&dto.Quantile{ | ||||
| 									Quantile: proto.Float64(0.99), | ||||
| 									Value:    proto.Float64(0), | ||||
| 								}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 					&dto.Metric{ | ||||
| 						Label: []*dto.LabelPair{ | ||||
| 							&dto.LabelPair{ | ||||
| 								Name:  proto.String("name_1"), | ||||
| 								Value: proto.String("value 1"), | ||||
| 							}, | ||||
| 							&dto.LabelPair{ | ||||
| 								Name:  proto.String("name_2"), | ||||
| 								Value: proto.String("value 2"), | ||||
| 							}, | ||||
| 						}, | ||||
| 						Summary: &dto.Summary{ | ||||
| 							SampleCount: proto.Uint64(4711), | ||||
| 							SampleSum:   proto.Float64(2010.1971), | ||||
| 							Quantile: []*dto.Quantile{ | ||||
| 								&dto.Quantile{ | ||||
| 									Quantile: proto.Float64(0.5), | ||||
| 									Value:    proto.Float64(1), | ||||
| 								}, | ||||
| 								&dto.Quantile{ | ||||
| 									Quantile: proto.Float64(0.9), | ||||
| 									Value:    proto.Float64(2), | ||||
| 								}, | ||||
| 								&dto.Quantile{ | ||||
| 									Quantile: proto.Float64(0.99), | ||||
| 									Value:    proto.Float64(3), | ||||
| 								}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			out: `# HELP summary_name summary docstring | ||||
| # TYPE summary_name summary | ||||
| summary_name{quantile="0.5"} -1.23 | ||||
| summary_name{quantile="0.9"} 0.2342354 | ||||
| summary_name{quantile="0.99"} 0 | ||||
| summary_name_sum -3.4567 | ||||
| summary_name_count 42 | ||||
| summary_name{name_1="value 1",name_2="value 2",quantile="0.5"} 1 | ||||
| summary_name{name_1="value 1",name_2="value 2",quantile="0.9"} 2 | ||||
| summary_name{name_1="value 1",name_2="value 2",quantile="0.99"} 3 | ||||
| summary_name_sum{name_1="value 1",name_2="value 2"} 2010.1971 | ||||
| summary_name_count{name_1="value 1",name_2="value 2"} 4711 | ||||
| `, | ||||
| 		}, | ||||
| 		// 4: Histogram | ||||
| 		{ | ||||
| 			in: &dto.MetricFamily{ | ||||
| 				Name: proto.String("request_duration_microseconds"), | ||||
| 				Help: proto.String("The response latency."), | ||||
| 				Type: dto.MetricType_HISTOGRAM.Enum(), | ||||
| 				Metric: []*dto.Metric{ | ||||
| 					&dto.Metric{ | ||||
| 						Histogram: &dto.Histogram{ | ||||
| 							SampleCount: proto.Uint64(2693), | ||||
| 							SampleSum:   proto.Float64(1756047.3), | ||||
| 							Bucket: []*dto.Bucket{ | ||||
| 								&dto.Bucket{ | ||||
| 									UpperBound:      proto.Float64(100), | ||||
| 									CumulativeCount: proto.Uint64(123), | ||||
| 								}, | ||||
| 								&dto.Bucket{ | ||||
| 									UpperBound:      proto.Float64(120), | ||||
| 									CumulativeCount: proto.Uint64(412), | ||||
| 								}, | ||||
| 								&dto.Bucket{ | ||||
| 									UpperBound:      proto.Float64(144), | ||||
| 									CumulativeCount: proto.Uint64(592), | ||||
| 								}, | ||||
| 								&dto.Bucket{ | ||||
| 									UpperBound:      proto.Float64(172.8), | ||||
| 									CumulativeCount: proto.Uint64(1524), | ||||
| 								}, | ||||
| 								&dto.Bucket{ | ||||
| 									UpperBound:      proto.Float64(math.Inf(+1)), | ||||
| 									CumulativeCount: proto.Uint64(2693), | ||||
| 								}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			out: `# HELP request_duration_microseconds The response latency. | ||||
| # TYPE request_duration_microseconds histogram | ||||
| request_duration_microseconds_bucket{le="100"} 123 | ||||
| request_duration_microseconds_bucket{le="120"} 412 | ||||
| request_duration_microseconds_bucket{le="144"} 592 | ||||
| request_duration_microseconds_bucket{le="172.8"} 1524 | ||||
| request_duration_microseconds_bucket{le="+Inf"} 2693 | ||||
| request_duration_microseconds_sum 1.7560473e+06 | ||||
| request_duration_microseconds_count 2693 | ||||
| `, | ||||
| 		}, | ||||
| 		// 5: Histogram with missing +Inf bucket. | ||||
| 		{ | ||||
| 			in: &dto.MetricFamily{ | ||||
| 				Name: proto.String("request_duration_microseconds"), | ||||
| 				Help: proto.String("The response latency."), | ||||
| 				Type: dto.MetricType_HISTOGRAM.Enum(), | ||||
| 				Metric: []*dto.Metric{ | ||||
| 					&dto.Metric{ | ||||
| 						Histogram: &dto.Histogram{ | ||||
| 							SampleCount: proto.Uint64(2693), | ||||
| 							SampleSum:   proto.Float64(1756047.3), | ||||
| 							Bucket: []*dto.Bucket{ | ||||
| 								&dto.Bucket{ | ||||
| 									UpperBound:      proto.Float64(100), | ||||
| 									CumulativeCount: proto.Uint64(123), | ||||
| 								}, | ||||
| 								&dto.Bucket{ | ||||
| 									UpperBound:      proto.Float64(120), | ||||
| 									CumulativeCount: proto.Uint64(412), | ||||
| 								}, | ||||
| 								&dto.Bucket{ | ||||
| 									UpperBound:      proto.Float64(144), | ||||
| 									CumulativeCount: proto.Uint64(592), | ||||
| 								}, | ||||
| 								&dto.Bucket{ | ||||
| 									UpperBound:      proto.Float64(172.8), | ||||
| 									CumulativeCount: proto.Uint64(1524), | ||||
| 								}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			out: `# HELP request_duration_microseconds The response latency. | ||||
| # TYPE request_duration_microseconds histogram | ||||
| request_duration_microseconds_bucket{le="100"} 123 | ||||
| request_duration_microseconds_bucket{le="120"} 412 | ||||
| request_duration_microseconds_bucket{le="144"} 592 | ||||
| request_duration_microseconds_bucket{le="172.8"} 1524 | ||||
| request_duration_microseconds_bucket{le="+Inf"} 2693 | ||||
| request_duration_microseconds_sum 1.7560473e+06 | ||||
| request_duration_microseconds_count 2693 | ||||
| `, | ||||
| 		}, | ||||
| 		// 6: No metric type, should result in default type Counter. | ||||
| 		{ | ||||
| 			in: &dto.MetricFamily{ | ||||
| 				Name: proto.String("name"), | ||||
| 				Help: proto.String("doc string"), | ||||
| 				Metric: []*dto.Metric{ | ||||
| 					&dto.Metric{ | ||||
| 						Counter: &dto.Counter{ | ||||
| 							Value: proto.Float64(math.Inf(-1)), | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			out: `# HELP name doc string | ||||
| # TYPE name counter | ||||
| name -Inf | ||||
| `, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, scenario := range scenarios { | ||||
| 		out := bytes.NewBuffer(make([]byte, 0, len(scenario.out))) | ||||
| 		n, err := MetricFamilyToText(out, scenario.in) | ||||
| 		if err != nil { | ||||
| 			t.Errorf("%d. error: %s", i, err) | ||||
| 			continue | ||||
| 		} | ||||
| 		if expected, got := len(scenario.out), n; expected != got { | ||||
| 			t.Errorf( | ||||
| 				"%d. expected %d bytes written, got %d", | ||||
| 				i, expected, got, | ||||
| 			) | ||||
| 		} | ||||
| 		if expected, got := scenario.out, out.String(); expected != got { | ||||
| 			t.Errorf( | ||||
| 				"%d. expected out=%q, got %q", | ||||
| 				i, expected, got, | ||||
| 			) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| func TestCreate(t *testing.T) { | ||||
| 	testCreate(t) | ||||
| } | ||||
|  | ||||
| func BenchmarkCreate(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		testCreate(b) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func testCreateError(t testing.TB) { | ||||
| 	var scenarios = []struct { | ||||
| 		in  *dto.MetricFamily | ||||
| 		err string | ||||
| 	}{ | ||||
| 		// 0: No metric. | ||||
| 		{ | ||||
| 			in: &dto.MetricFamily{ | ||||
| 				Name:   proto.String("name"), | ||||
| 				Help:   proto.String("doc string"), | ||||
| 				Type:   dto.MetricType_COUNTER.Enum(), | ||||
| 				Metric: []*dto.Metric{}, | ||||
| 			}, | ||||
| 			err: "MetricFamily has no metrics", | ||||
| 		}, | ||||
| 		// 1: No metric name. | ||||
| 		{ | ||||
| 			in: &dto.MetricFamily{ | ||||
| 				Help: proto.String("doc string"), | ||||
| 				Type: dto.MetricType_UNTYPED.Enum(), | ||||
| 				Metric: []*dto.Metric{ | ||||
| 					&dto.Metric{ | ||||
| 						Untyped: &dto.Untyped{ | ||||
| 							Value: proto.Float64(math.Inf(-1)), | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			err: "MetricFamily has no name", | ||||
| 		}, | ||||
| 		// 2: Wrong type. | ||||
| 		{ | ||||
| 			in: &dto.MetricFamily{ | ||||
| 				Name: proto.String("name"), | ||||
| 				Help: proto.String("doc string"), | ||||
| 				Type: dto.MetricType_COUNTER.Enum(), | ||||
| 				Metric: []*dto.Metric{ | ||||
| 					&dto.Metric{ | ||||
| 						Untyped: &dto.Untyped{ | ||||
| 							Value: proto.Float64(math.Inf(-1)), | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			err: "expected counter in metric", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, scenario := range scenarios { | ||||
| 		var out bytes.Buffer | ||||
| 		_, err := MetricFamilyToText(&out, scenario.in) | ||||
| 		if err == nil { | ||||
| 			t.Errorf("%d. expected error, got nil", i) | ||||
| 			continue | ||||
| 		} | ||||
| 		if expected, got := scenario.err, err.Error(); strings.Index(got, expected) != 0 { | ||||
| 			t.Errorf( | ||||
| 				"%d. expected error starting with %q, got %q", | ||||
| 				i, expected, got, | ||||
| 			) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| func TestCreateError(t *testing.T) { | ||||
| 	testCreateError(t) | ||||
| } | ||||
|  | ||||
| func BenchmarkCreateError(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		testCreateError(b) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										593
									
								
								vendor/github.com/prometheus/common/expfmt/text_parse_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										593
									
								
								vendor/github.com/prometheus/common/expfmt/text_parse_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,593 +0,0 @@ | ||||
| // Copyright 2014 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 expfmt | ||||
|  | ||||
| import ( | ||||
| 	"math" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| 	dto "github.com/prometheus/client_model/go" | ||||
| ) | ||||
|  | ||||
| func testTextParse(t testing.TB) { | ||||
| 	var scenarios = []struct { | ||||
| 		in  string | ||||
| 		out []*dto.MetricFamily | ||||
| 	}{ | ||||
| 		// 0: Empty lines as input. | ||||
| 		{ | ||||
| 			in: ` | ||||
|  | ||||
| `, | ||||
| 			out: []*dto.MetricFamily{}, | ||||
| 		}, | ||||
| 		// 1: Minimal case. | ||||
| 		{ | ||||
| 			in: ` | ||||
| minimal_metric 1.234 | ||||
| another_metric -3e3 103948 | ||||
| # Even that: | ||||
| no_labels{} 3 | ||||
| # HELP line for non-existing metric will be ignored. | ||||
| `, | ||||
| 			out: []*dto.MetricFamily{ | ||||
| 				&dto.MetricFamily{ | ||||
| 					Name: proto.String("minimal_metric"), | ||||
| 					Type: dto.MetricType_UNTYPED.Enum(), | ||||
| 					Metric: []*dto.Metric{ | ||||
| 						&dto.Metric{ | ||||
| 							Untyped: &dto.Untyped{ | ||||
| 								Value: proto.Float64(1.234), | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				&dto.MetricFamily{ | ||||
| 					Name: proto.String("another_metric"), | ||||
| 					Type: dto.MetricType_UNTYPED.Enum(), | ||||
| 					Metric: []*dto.Metric{ | ||||
| 						&dto.Metric{ | ||||
| 							Untyped: &dto.Untyped{ | ||||
| 								Value: proto.Float64(-3e3), | ||||
| 							}, | ||||
| 							TimestampMs: proto.Int64(103948), | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				&dto.MetricFamily{ | ||||
| 					Name: proto.String("no_labels"), | ||||
| 					Type: dto.MetricType_UNTYPED.Enum(), | ||||
| 					Metric: []*dto.Metric{ | ||||
| 						&dto.Metric{ | ||||
| 							Untyped: &dto.Untyped{ | ||||
| 								Value: proto.Float64(3), | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		// 2: Counters & gauges, docstrings, various whitespace, escape sequences. | ||||
| 		{ | ||||
| 			in: ` | ||||
| # A normal comment. | ||||
| # | ||||
| # TYPE name counter | ||||
| name{labelname="val1",basename="basevalue"} NaN | ||||
| name {labelname="val2",basename="base\"v\\al\nue"} 0.23 1234567890 | ||||
| # HELP name two-line\n doc  str\\ing | ||||
|  | ||||
|  # HELP  name2  	doc str"ing 2 | ||||
|   #    TYPE    name2 gauge | ||||
| name2{labelname="val2"	,basename   =   "basevalue2"		} +Inf 54321 | ||||
| name2{ labelname = "val1" , }-Inf | ||||
| `, | ||||
| 			out: []*dto.MetricFamily{ | ||||
| 				&dto.MetricFamily{ | ||||
| 					Name: proto.String("name"), | ||||
| 					Help: proto.String("two-line\n doc  str\\ing"), | ||||
| 					Type: dto.MetricType_COUNTER.Enum(), | ||||
| 					Metric: []*dto.Metric{ | ||||
| 						&dto.Metric{ | ||||
| 							Label: []*dto.LabelPair{ | ||||
| 								&dto.LabelPair{ | ||||
| 									Name:  proto.String("labelname"), | ||||
| 									Value: proto.String("val1"), | ||||
| 								}, | ||||
| 								&dto.LabelPair{ | ||||
| 									Name:  proto.String("basename"), | ||||
| 									Value: proto.String("basevalue"), | ||||
| 								}, | ||||
| 							}, | ||||
| 							Counter: &dto.Counter{ | ||||
| 								Value: proto.Float64(math.NaN()), | ||||
| 							}, | ||||
| 						}, | ||||
| 						&dto.Metric{ | ||||
| 							Label: []*dto.LabelPair{ | ||||
| 								&dto.LabelPair{ | ||||
| 									Name:  proto.String("labelname"), | ||||
| 									Value: proto.String("val2"), | ||||
| 								}, | ||||
| 								&dto.LabelPair{ | ||||
| 									Name:  proto.String("basename"), | ||||
| 									Value: proto.String("base\"v\\al\nue"), | ||||
| 								}, | ||||
| 							}, | ||||
| 							Counter: &dto.Counter{ | ||||
| 								Value: proto.Float64(.23), | ||||
| 							}, | ||||
| 							TimestampMs: proto.Int64(1234567890), | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				&dto.MetricFamily{ | ||||
| 					Name: proto.String("name2"), | ||||
| 					Help: proto.String("doc str\"ing 2"), | ||||
| 					Type: dto.MetricType_GAUGE.Enum(), | ||||
| 					Metric: []*dto.Metric{ | ||||
| 						&dto.Metric{ | ||||
| 							Label: []*dto.LabelPair{ | ||||
| 								&dto.LabelPair{ | ||||
| 									Name:  proto.String("labelname"), | ||||
| 									Value: proto.String("val2"), | ||||
| 								}, | ||||
| 								&dto.LabelPair{ | ||||
| 									Name:  proto.String("basename"), | ||||
| 									Value: proto.String("basevalue2"), | ||||
| 								}, | ||||
| 							}, | ||||
| 							Gauge: &dto.Gauge{ | ||||
| 								Value: proto.Float64(math.Inf(+1)), | ||||
| 							}, | ||||
| 							TimestampMs: proto.Int64(54321), | ||||
| 						}, | ||||
| 						&dto.Metric{ | ||||
| 							Label: []*dto.LabelPair{ | ||||
| 								&dto.LabelPair{ | ||||
| 									Name:  proto.String("labelname"), | ||||
| 									Value: proto.String("val1"), | ||||
| 								}, | ||||
| 							}, | ||||
| 							Gauge: &dto.Gauge{ | ||||
| 								Value: proto.Float64(math.Inf(-1)), | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		// 3: The evil summary, mixed with other types and funny comments. | ||||
| 		{ | ||||
| 			in: ` | ||||
| # TYPE my_summary summary | ||||
| my_summary{n1="val1",quantile="0.5"} 110 | ||||
| decoy -1 -2 | ||||
| my_summary{n1="val1",quantile="0.9"} 140 1 | ||||
| my_summary_count{n1="val1"} 42 | ||||
| # Latest timestamp wins in case of a summary. | ||||
| my_summary_sum{n1="val1"} 4711 2 | ||||
| fake_sum{n1="val1"} 2001 | ||||
| # TYPE another_summary summary | ||||
| another_summary_count{n2="val2",n1="val1"} 20 | ||||
| my_summary_count{n2="val2",n1="val1"} 5 5 | ||||
| another_summary{n1="val1",n2="val2",quantile=".3"} -1.2 | ||||
| my_summary_sum{n1="val2"} 08 15 | ||||
| my_summary{n1="val3", quantile="0.2"} 4711 | ||||
|   my_summary{n1="val1",n2="val2",quantile="-12.34",} NaN | ||||
| # some | ||||
| # funny comments | ||||
| # HELP  | ||||
| # HELP | ||||
| # HELP my_summary | ||||
| # HELP my_summary  | ||||
| `, | ||||
| 			out: []*dto.MetricFamily{ | ||||
| 				&dto.MetricFamily{ | ||||
| 					Name: proto.String("fake_sum"), | ||||
| 					Type: dto.MetricType_UNTYPED.Enum(), | ||||
| 					Metric: []*dto.Metric{ | ||||
| 						&dto.Metric{ | ||||
| 							Label: []*dto.LabelPair{ | ||||
| 								&dto.LabelPair{ | ||||
| 									Name:  proto.String("n1"), | ||||
| 									Value: proto.String("val1"), | ||||
| 								}, | ||||
| 							}, | ||||
| 							Untyped: &dto.Untyped{ | ||||
| 								Value: proto.Float64(2001), | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				&dto.MetricFamily{ | ||||
| 					Name: proto.String("decoy"), | ||||
| 					Type: dto.MetricType_UNTYPED.Enum(), | ||||
| 					Metric: []*dto.Metric{ | ||||
| 						&dto.Metric{ | ||||
| 							Untyped: &dto.Untyped{ | ||||
| 								Value: proto.Float64(-1), | ||||
| 							}, | ||||
| 							TimestampMs: proto.Int64(-2), | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				&dto.MetricFamily{ | ||||
| 					Name: proto.String("my_summary"), | ||||
| 					Type: dto.MetricType_SUMMARY.Enum(), | ||||
| 					Metric: []*dto.Metric{ | ||||
| 						&dto.Metric{ | ||||
| 							Label: []*dto.LabelPair{ | ||||
| 								&dto.LabelPair{ | ||||
| 									Name:  proto.String("n1"), | ||||
| 									Value: proto.String("val1"), | ||||
| 								}, | ||||
| 							}, | ||||
| 							Summary: &dto.Summary{ | ||||
| 								SampleCount: proto.Uint64(42), | ||||
| 								SampleSum:   proto.Float64(4711), | ||||
| 								Quantile: []*dto.Quantile{ | ||||
| 									&dto.Quantile{ | ||||
| 										Quantile: proto.Float64(0.5), | ||||
| 										Value:    proto.Float64(110), | ||||
| 									}, | ||||
| 									&dto.Quantile{ | ||||
| 										Quantile: proto.Float64(0.9), | ||||
| 										Value:    proto.Float64(140), | ||||
| 									}, | ||||
| 								}, | ||||
| 							}, | ||||
| 							TimestampMs: proto.Int64(2), | ||||
| 						}, | ||||
| 						&dto.Metric{ | ||||
| 							Label: []*dto.LabelPair{ | ||||
| 								&dto.LabelPair{ | ||||
| 									Name:  proto.String("n2"), | ||||
| 									Value: proto.String("val2"), | ||||
| 								}, | ||||
| 								&dto.LabelPair{ | ||||
| 									Name:  proto.String("n1"), | ||||
| 									Value: proto.String("val1"), | ||||
| 								}, | ||||
| 							}, | ||||
| 							Summary: &dto.Summary{ | ||||
| 								SampleCount: proto.Uint64(5), | ||||
| 								Quantile: []*dto.Quantile{ | ||||
| 									&dto.Quantile{ | ||||
| 										Quantile: proto.Float64(-12.34), | ||||
| 										Value:    proto.Float64(math.NaN()), | ||||
| 									}, | ||||
| 								}, | ||||
| 							}, | ||||
| 							TimestampMs: proto.Int64(5), | ||||
| 						}, | ||||
| 						&dto.Metric{ | ||||
| 							Label: []*dto.LabelPair{ | ||||
| 								&dto.LabelPair{ | ||||
| 									Name:  proto.String("n1"), | ||||
| 									Value: proto.String("val2"), | ||||
| 								}, | ||||
| 							}, | ||||
| 							Summary: &dto.Summary{ | ||||
| 								SampleSum: proto.Float64(8), | ||||
| 							}, | ||||
| 							TimestampMs: proto.Int64(15), | ||||
| 						}, | ||||
| 						&dto.Metric{ | ||||
| 							Label: []*dto.LabelPair{ | ||||
| 								&dto.LabelPair{ | ||||
| 									Name:  proto.String("n1"), | ||||
| 									Value: proto.String("val3"), | ||||
| 								}, | ||||
| 							}, | ||||
| 							Summary: &dto.Summary{ | ||||
| 								Quantile: []*dto.Quantile{ | ||||
| 									&dto.Quantile{ | ||||
| 										Quantile: proto.Float64(0.2), | ||||
| 										Value:    proto.Float64(4711), | ||||
| 									}, | ||||
| 								}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 				&dto.MetricFamily{ | ||||
| 					Name: proto.String("another_summary"), | ||||
| 					Type: dto.MetricType_SUMMARY.Enum(), | ||||
| 					Metric: []*dto.Metric{ | ||||
| 						&dto.Metric{ | ||||
| 							Label: []*dto.LabelPair{ | ||||
| 								&dto.LabelPair{ | ||||
| 									Name:  proto.String("n2"), | ||||
| 									Value: proto.String("val2"), | ||||
| 								}, | ||||
| 								&dto.LabelPair{ | ||||
| 									Name:  proto.String("n1"), | ||||
| 									Value: proto.String("val1"), | ||||
| 								}, | ||||
| 							}, | ||||
| 							Summary: &dto.Summary{ | ||||
| 								SampleCount: proto.Uint64(20), | ||||
| 								Quantile: []*dto.Quantile{ | ||||
| 									&dto.Quantile{ | ||||
| 										Quantile: proto.Float64(0.3), | ||||
| 										Value:    proto.Float64(-1.2), | ||||
| 									}, | ||||
| 								}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		// 4: The histogram. | ||||
| 		{ | ||||
| 			in: ` | ||||
| # HELP request_duration_microseconds The response latency. | ||||
| # TYPE request_duration_microseconds histogram | ||||
| request_duration_microseconds_bucket{le="100"} 123 | ||||
| request_duration_microseconds_bucket{le="120"} 412 | ||||
| request_duration_microseconds_bucket{le="144"} 592 | ||||
| request_duration_microseconds_bucket{le="172.8"} 1524 | ||||
| request_duration_microseconds_bucket{le="+Inf"} 2693 | ||||
| request_duration_microseconds_sum 1.7560473e+06 | ||||
| request_duration_microseconds_count 2693 | ||||
| `, | ||||
| 			out: []*dto.MetricFamily{ | ||||
| 				{ | ||||
| 					Name: proto.String("request_duration_microseconds"), | ||||
| 					Help: proto.String("The response latency."), | ||||
| 					Type: dto.MetricType_HISTOGRAM.Enum(), | ||||
| 					Metric: []*dto.Metric{ | ||||
| 						&dto.Metric{ | ||||
| 							Histogram: &dto.Histogram{ | ||||
| 								SampleCount: proto.Uint64(2693), | ||||
| 								SampleSum:   proto.Float64(1756047.3), | ||||
| 								Bucket: []*dto.Bucket{ | ||||
| 									&dto.Bucket{ | ||||
| 										UpperBound:      proto.Float64(100), | ||||
| 										CumulativeCount: proto.Uint64(123), | ||||
| 									}, | ||||
| 									&dto.Bucket{ | ||||
| 										UpperBound:      proto.Float64(120), | ||||
| 										CumulativeCount: proto.Uint64(412), | ||||
| 									}, | ||||
| 									&dto.Bucket{ | ||||
| 										UpperBound:      proto.Float64(144), | ||||
| 										CumulativeCount: proto.Uint64(592), | ||||
| 									}, | ||||
| 									&dto.Bucket{ | ||||
| 										UpperBound:      proto.Float64(172.8), | ||||
| 										CumulativeCount: proto.Uint64(1524), | ||||
| 									}, | ||||
| 									&dto.Bucket{ | ||||
| 										UpperBound:      proto.Float64(math.Inf(+1)), | ||||
| 										CumulativeCount: proto.Uint64(2693), | ||||
| 									}, | ||||
| 								}, | ||||
| 							}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, scenario := range scenarios { | ||||
| 		out, err := parser.TextToMetricFamilies(strings.NewReader(scenario.in)) | ||||
| 		if err != nil { | ||||
| 			t.Errorf("%d. error: %s", i, err) | ||||
| 			continue | ||||
| 		} | ||||
| 		if expected, got := len(scenario.out), len(out); expected != got { | ||||
| 			t.Errorf( | ||||
| 				"%d. expected %d MetricFamilies, got %d", | ||||
| 				i, expected, got, | ||||
| 			) | ||||
| 		} | ||||
| 		for _, expected := range scenario.out { | ||||
| 			got, ok := out[expected.GetName()] | ||||
| 			if !ok { | ||||
| 				t.Errorf( | ||||
| 					"%d. expected MetricFamily %q, found none", | ||||
| 					i, expected.GetName(), | ||||
| 				) | ||||
| 				continue | ||||
| 			} | ||||
| 			if expected.String() != got.String() { | ||||
| 				t.Errorf( | ||||
| 					"%d. expected MetricFamily %s, got %s", | ||||
| 					i, expected, got, | ||||
| 				) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestTextParse(t *testing.T) { | ||||
| 	testTextParse(t) | ||||
| } | ||||
|  | ||||
| func BenchmarkTextParse(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		testTextParse(b) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func testTextParseError(t testing.TB) { | ||||
| 	var scenarios = []struct { | ||||
| 		in  string | ||||
| 		err string | ||||
| 	}{ | ||||
| 		// 0: No new-line at end of input. | ||||
| 		{ | ||||
| 			in: ` | ||||
| bla 3.14 | ||||
| blubber 42`, | ||||
| 			err: "text format parsing error in line 3: unexpected end of input stream", | ||||
| 		}, | ||||
| 		// 1: Invalid escape sequence in label value. | ||||
| 		{ | ||||
| 			in:  `metric{label="\t"} 3.14`, | ||||
| 			err: "text format parsing error in line 1: invalid escape sequence", | ||||
| 		}, | ||||
| 		// 2: Newline in label value. | ||||
| 		{ | ||||
| 			in: ` | ||||
| metric{label="new | ||||
| line"} 3.14 | ||||
| `, | ||||
| 			err: `text format parsing error in line 2: label value "new" contains unescaped new-line`, | ||||
| 		}, | ||||
| 		// 3: | ||||
| 		{ | ||||
| 			in:  `metric{@="bla"} 3.14`, | ||||
| 			err: "text format parsing error in line 1: invalid label name for metric", | ||||
| 		}, | ||||
| 		// 4: | ||||
| 		{ | ||||
| 			in:  `metric{__name__="bla"} 3.14`, | ||||
| 			err: `text format parsing error in line 1: label name "__name__" is reserved`, | ||||
| 		}, | ||||
| 		// 5: | ||||
| 		{ | ||||
| 			in:  `metric{label+="bla"} 3.14`, | ||||
| 			err: "text format parsing error in line 1: expected '=' after label name", | ||||
| 		}, | ||||
| 		// 6: | ||||
| 		{ | ||||
| 			in:  `metric{label=bla} 3.14`, | ||||
| 			err: "text format parsing error in line 1: expected '\"' at start of label value", | ||||
| 		}, | ||||
| 		// 7: | ||||
| 		{ | ||||
| 			in: ` | ||||
| # TYPE metric summary | ||||
| metric{quantile="bla"} 3.14 | ||||
| `, | ||||
| 			err: "text format parsing error in line 3: expected float as value for 'quantile' label", | ||||
| 		}, | ||||
| 		// 8: | ||||
| 		{ | ||||
| 			in:  `metric{label="bla"+} 3.14`, | ||||
| 			err: "text format parsing error in line 1: unexpected end of label value", | ||||
| 		}, | ||||
| 		// 9: | ||||
| 		{ | ||||
| 			in: `metric{label="bla"} 3.14 2.72 | ||||
| `, | ||||
| 			err: "text format parsing error in line 1: expected integer as timestamp", | ||||
| 		}, | ||||
| 		// 10: | ||||
| 		{ | ||||
| 			in: `metric{label="bla"} 3.14 2 3 | ||||
| `, | ||||
| 			err: "text format parsing error in line 1: spurious string after timestamp", | ||||
| 		}, | ||||
| 		// 11: | ||||
| 		{ | ||||
| 			in: `metric{label="bla"} blubb | ||||
| `, | ||||
| 			err: "text format parsing error in line 1: expected float as value", | ||||
| 		}, | ||||
| 		// 12: | ||||
| 		{ | ||||
| 			in: ` | ||||
| # HELP metric one | ||||
| # HELP metric two | ||||
| `, | ||||
| 			err: "text format parsing error in line 3: second HELP line for metric name", | ||||
| 		}, | ||||
| 		// 13: | ||||
| 		{ | ||||
| 			in: ` | ||||
| # TYPE metric counter | ||||
| # TYPE metric untyped | ||||
| `, | ||||
| 			err: `text format parsing error in line 3: second TYPE line for metric name "metric", or TYPE reported after samples`, | ||||
| 		}, | ||||
| 		// 14: | ||||
| 		{ | ||||
| 			in: ` | ||||
| metric 4.12 | ||||
| # TYPE metric counter | ||||
| `, | ||||
| 			err: `text format parsing error in line 3: second TYPE line for metric name "metric", or TYPE reported after samples`, | ||||
| 		}, | ||||
| 		// 14: | ||||
| 		{ | ||||
| 			in: ` | ||||
| # TYPE metric bla | ||||
| `, | ||||
| 			err: "text format parsing error in line 2: unknown metric type", | ||||
| 		}, | ||||
| 		// 15: | ||||
| 		{ | ||||
| 			in: ` | ||||
| # TYPE met-ric | ||||
| `, | ||||
| 			err: "text format parsing error in line 2: invalid metric name in comment", | ||||
| 		}, | ||||
| 		// 16: | ||||
| 		{ | ||||
| 			in:  `@invalidmetric{label="bla"} 3.14 2`, | ||||
| 			err: "text format parsing error in line 1: invalid metric name", | ||||
| 		}, | ||||
| 		// 17: | ||||
| 		{ | ||||
| 			in:  `{label="bla"} 3.14 2`, | ||||
| 			err: "text format parsing error in line 1: invalid metric name", | ||||
| 		}, | ||||
| 		// 18: | ||||
| 		{ | ||||
| 			in: ` | ||||
| # TYPE metric histogram | ||||
| metric_bucket{le="bla"} 3.14 | ||||
| `, | ||||
| 			err: "text format parsing error in line 3: expected float as value for 'le' label", | ||||
| 		}, | ||||
| 		// 19: Invalid UTF-8 in label value. | ||||
| 		{ | ||||
| 			in:  "metric{l=\"\xbd\"} 3.14\n", | ||||
| 			err: "text format parsing error in line 1: invalid label value \"\\xbd\"", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, scenario := range scenarios { | ||||
| 		_, err := parser.TextToMetricFamilies(strings.NewReader(scenario.in)) | ||||
| 		if err == nil { | ||||
| 			t.Errorf("%d. expected error, got nil", i) | ||||
| 			continue | ||||
| 		} | ||||
| 		if expected, got := scenario.err, err.Error(); strings.Index(got, expected) != 0 { | ||||
| 			t.Errorf( | ||||
| 				"%d. expected error starting with %q, got %q", | ||||
| 				i, expected, got, | ||||
| 			) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| func TestTextParseError(t *testing.T) { | ||||
| 	testTextParseError(t) | ||||
| } | ||||
|  | ||||
| func BenchmarkParseError(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		testTextParseError(b) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										33
									
								
								vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								vendor/github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg/autoneg_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,33 +0,0 @@ | ||||
| package goautoneg | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| var chrome = "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5" | ||||
|  | ||||
| func TestParseAccept(t *testing.T) { | ||||
| 	alternatives := []string{"text/html", "image/png"} | ||||
| 	content_type := Negotiate(chrome, alternatives) | ||||
| 	if content_type != "image/png" { | ||||
| 		t.Errorf("got %s expected image/png", content_type) | ||||
| 	} | ||||
|  | ||||
| 	alternatives = []string{"text/html", "text/plain", "text/n3"} | ||||
| 	content_type = Negotiate(chrome, alternatives) | ||||
| 	if content_type != "text/html" { | ||||
| 		t.Errorf("got %s expected text/html", content_type) | ||||
| 	} | ||||
|  | ||||
| 	alternatives = []string{"text/n3", "text/plain"} | ||||
| 	content_type = Negotiate(chrome, alternatives) | ||||
| 	if content_type != "text/plain" { | ||||
| 		t.Errorf("got %s expected text/plain", content_type) | ||||
| 	} | ||||
|  | ||||
| 	alternatives = []string{"text/n3", "application/rdf+xml"} | ||||
| 	content_type = Negotiate(chrome, alternatives) | ||||
| 	if content_type != "text/n3" { | ||||
| 		t.Errorf("got %s expected text/n3", content_type) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										118
									
								
								vendor/github.com/prometheus/common/model/alert_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										118
									
								
								vendor/github.com/prometheus/common/model/alert_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,118 +0,0 @@ | ||||
| // Copyright 2013 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 model | ||||
|  | ||||
| import ( | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| func TestAlertValidate(t *testing.T) { | ||||
| 	ts := time.Now() | ||||
|  | ||||
| 	var cases = []struct { | ||||
| 		alert *Alert | ||||
| 		err   string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			alert: &Alert{ | ||||
| 				Labels:   LabelSet{"a": "b"}, | ||||
| 				StartsAt: ts, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			alert: &Alert{ | ||||
| 				Labels: LabelSet{"a": "b"}, | ||||
| 			}, | ||||
| 			err: "start time missing", | ||||
| 		}, | ||||
| 		{ | ||||
| 			alert: &Alert{ | ||||
| 				Labels:   LabelSet{"a": "b"}, | ||||
| 				StartsAt: ts, | ||||
| 				EndsAt:   ts, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			alert: &Alert{ | ||||
| 				Labels:   LabelSet{"a": "b"}, | ||||
| 				StartsAt: ts, | ||||
| 				EndsAt:   ts.Add(1 * time.Minute), | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			alert: &Alert{ | ||||
| 				Labels:   LabelSet{"a": "b"}, | ||||
| 				StartsAt: ts, | ||||
| 				EndsAt:   ts.Add(-1 * time.Minute), | ||||
| 			}, | ||||
| 			err: "start time must be before end time", | ||||
| 		}, | ||||
| 		{ | ||||
| 			alert: &Alert{ | ||||
| 				StartsAt: ts, | ||||
| 			}, | ||||
| 			err: "at least one label pair required", | ||||
| 		}, | ||||
| 		{ | ||||
| 			alert: &Alert{ | ||||
| 				Labels:   LabelSet{"a": "b", "!bad": "label"}, | ||||
| 				StartsAt: ts, | ||||
| 			}, | ||||
| 			err: "invalid label set: invalid name", | ||||
| 		}, | ||||
| 		{ | ||||
| 			alert: &Alert{ | ||||
| 				Labels:   LabelSet{"a": "b", "bad": "\xfflabel"}, | ||||
| 				StartsAt: ts, | ||||
| 			}, | ||||
| 			err: "invalid label set: invalid value", | ||||
| 		}, | ||||
| 		{ | ||||
| 			alert: &Alert{ | ||||
| 				Labels:      LabelSet{"a": "b"}, | ||||
| 				Annotations: LabelSet{"!bad": "label"}, | ||||
| 				StartsAt:    ts, | ||||
| 			}, | ||||
| 			err: "invalid annotations: invalid name", | ||||
| 		}, | ||||
| 		{ | ||||
| 			alert: &Alert{ | ||||
| 				Labels:      LabelSet{"a": "b"}, | ||||
| 				Annotations: LabelSet{"bad": "\xfflabel"}, | ||||
| 				StartsAt:    ts, | ||||
| 			}, | ||||
| 			err: "invalid annotations: invalid value", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, c := range cases { | ||||
| 		err := c.alert.Validate() | ||||
| 		if err == nil { | ||||
| 			if c.err == "" { | ||||
| 				continue | ||||
| 			} | ||||
| 			t.Errorf("%d. Expected error %q but got none", i, c.err) | ||||
| 			continue | ||||
| 		} | ||||
| 		if c.err == "" && err != nil { | ||||
| 			t.Errorf("%d. Expected no error but got %q", i, err) | ||||
| 			continue | ||||
| 		} | ||||
| 		if !strings.Contains(err.Error(), c.err) { | ||||
| 			t.Errorf("%d. Expected error to contain %q but got %q", i, c.err, err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										140
									
								
								vendor/github.com/prometheus/common/model/labels_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										140
									
								
								vendor/github.com/prometheus/common/model/labels_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,140 +0,0 @@ | ||||
| // Copyright 2013 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 model | ||||
|  | ||||
| import ( | ||||
| 	"sort" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func testLabelNames(t testing.TB) { | ||||
| 	var scenarios = []struct { | ||||
| 		in  LabelNames | ||||
| 		out LabelNames | ||||
| 	}{ | ||||
| 		{ | ||||
| 			in:  LabelNames{"ZZZ", "zzz"}, | ||||
| 			out: LabelNames{"ZZZ", "zzz"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in:  LabelNames{"aaa", "AAA"}, | ||||
| 			out: LabelNames{"AAA", "aaa"}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, scenario := range scenarios { | ||||
| 		sort.Sort(scenario.in) | ||||
|  | ||||
| 		for j, expected := range scenario.out { | ||||
| 			if expected != scenario.in[j] { | ||||
| 				t.Errorf("%d.%d expected %s, got %s", i, j, expected, scenario.in[j]) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestLabelNames(t *testing.T) { | ||||
| 	testLabelNames(t) | ||||
| } | ||||
|  | ||||
| func BenchmarkLabelNames(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		testLabelNames(b) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func testLabelValues(t testing.TB) { | ||||
| 	var scenarios = []struct { | ||||
| 		in  LabelValues | ||||
| 		out LabelValues | ||||
| 	}{ | ||||
| 		{ | ||||
| 			in:  LabelValues{"ZZZ", "zzz"}, | ||||
| 			out: LabelValues{"ZZZ", "zzz"}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in:  LabelValues{"aaa", "AAA"}, | ||||
| 			out: LabelValues{"AAA", "aaa"}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, scenario := range scenarios { | ||||
| 		sort.Sort(scenario.in) | ||||
|  | ||||
| 		for j, expected := range scenario.out { | ||||
| 			if expected != scenario.in[j] { | ||||
| 				t.Errorf("%d.%d expected %s, got %s", i, j, expected, scenario.in[j]) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestLabelValues(t *testing.T) { | ||||
| 	testLabelValues(t) | ||||
| } | ||||
|  | ||||
| func BenchmarkLabelValues(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		testLabelValues(b) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestLabelNameIsValid(t *testing.T) { | ||||
| 	var scenarios = []struct { | ||||
| 		ln    LabelName | ||||
| 		valid bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			ln:    "Avalid_23name", | ||||
| 			valid: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			ln:    "_Avalid_23name", | ||||
| 			valid: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			ln:    "1valid_23name", | ||||
| 			valid: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			ln:    "avalid_23name", | ||||
| 			valid: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			ln:    "Ava:lid_23name", | ||||
| 			valid: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			ln:    "a lid_23name", | ||||
| 			valid: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			ln:    ":leading_colon", | ||||
| 			valid: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			ln:    "colon:in:the:middle", | ||||
| 			valid: false, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, s := range scenarios { | ||||
| 		if s.ln.IsValid() != s.valid { | ||||
| 			t.Errorf("Expected %v for %q using IsValid method", s.valid, s.ln) | ||||
| 		} | ||||
| 		if LabelNameRE.MatchString(string(s.ln)) != s.valid { | ||||
| 			t.Errorf("Expected %v for %q using regexp match", s.valid, s.ln) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										132
									
								
								vendor/github.com/prometheus/common/model/metric_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										132
									
								
								vendor/github.com/prometheus/common/model/metric_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,132 +0,0 @@ | ||||
| // Copyright 2013 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 model | ||||
|  | ||||
| import "testing" | ||||
|  | ||||
| func testMetric(t testing.TB) { | ||||
| 	var scenarios = []struct { | ||||
| 		input           LabelSet | ||||
| 		fingerprint     Fingerprint | ||||
| 		fastFingerprint Fingerprint | ||||
| 	}{ | ||||
| 		{ | ||||
| 			input:           LabelSet{}, | ||||
| 			fingerprint:     14695981039346656037, | ||||
| 			fastFingerprint: 14695981039346656037, | ||||
| 		}, | ||||
| 		{ | ||||
| 			input: LabelSet{ | ||||
| 				"first_name":   "electro", | ||||
| 				"occupation":   "robot", | ||||
| 				"manufacturer": "westinghouse", | ||||
| 			}, | ||||
| 			fingerprint:     5911716720268894962, | ||||
| 			fastFingerprint: 11310079640881077873, | ||||
| 		}, | ||||
| 		{ | ||||
| 			input: LabelSet{ | ||||
| 				"x": "y", | ||||
| 			}, | ||||
| 			fingerprint:     8241431561484471700, | ||||
| 			fastFingerprint: 13948396922932177635, | ||||
| 		}, | ||||
| 		{ | ||||
| 			input: LabelSet{ | ||||
| 				"a": "bb", | ||||
| 				"b": "c", | ||||
| 			}, | ||||
| 			fingerprint:     3016285359649981711, | ||||
| 			fastFingerprint: 3198632812309449502, | ||||
| 		}, | ||||
| 		{ | ||||
| 			input: LabelSet{ | ||||
| 				"a":  "b", | ||||
| 				"bb": "c", | ||||
| 			}, | ||||
| 			fingerprint:     7122421792099404749, | ||||
| 			fastFingerprint: 5774953389407657638, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, scenario := range scenarios { | ||||
| 		input := Metric(scenario.input) | ||||
|  | ||||
| 		if scenario.fingerprint != input.Fingerprint() { | ||||
| 			t.Errorf("%d. expected %d, got %d", i, scenario.fingerprint, input.Fingerprint()) | ||||
| 		} | ||||
| 		if scenario.fastFingerprint != input.FastFingerprint() { | ||||
| 			t.Errorf("%d. expected %d, got %d", i, scenario.fastFingerprint, input.FastFingerprint()) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestMetric(t *testing.T) { | ||||
| 	testMetric(t) | ||||
| } | ||||
|  | ||||
| func BenchmarkMetric(b *testing.B) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		testMetric(b) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestMetricNameIsValid(t *testing.T) { | ||||
| 	var scenarios = []struct { | ||||
| 		mn    LabelValue | ||||
| 		valid bool | ||||
| 	}{ | ||||
| 		{ | ||||
| 			mn:    "Avalid_23name", | ||||
| 			valid: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			mn:    "_Avalid_23name", | ||||
| 			valid: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			mn:    "1valid_23name", | ||||
| 			valid: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			mn:    "avalid_23name", | ||||
| 			valid: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			mn:    "Ava:lid_23name", | ||||
| 			valid: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			mn:    "a lid_23name", | ||||
| 			valid: false, | ||||
| 		}, | ||||
| 		{ | ||||
| 			mn:    ":leading_colon", | ||||
| 			valid: true, | ||||
| 		}, | ||||
| 		{ | ||||
| 			mn:    "colon:in:the:middle", | ||||
| 			valid: true, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, s := range scenarios { | ||||
| 		if IsValidMetricName(s.mn) != s.valid { | ||||
| 			t.Errorf("Expected %v for %q using IsValidMetricName function", s.valid, s.mn) | ||||
| 		} | ||||
| 		if MetricNameRE.MatchString(string(s.mn)) != s.valid { | ||||
| 			t.Errorf("Expected %v for %q using regexp matching", s.valid, s.mn) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										314
									
								
								vendor/github.com/prometheus/common/model/signature_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										314
									
								
								vendor/github.com/prometheus/common/model/signature_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,314 +0,0 @@ | ||||
| // Copyright 2014 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 model | ||||
|  | ||||
| import ( | ||||
| 	"runtime" | ||||
| 	"sync" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestLabelsToSignature(t *testing.T) { | ||||
| 	var scenarios = []struct { | ||||
| 		in  map[string]string | ||||
| 		out uint64 | ||||
| 	}{ | ||||
| 		{ | ||||
| 			in:  map[string]string{}, | ||||
| 			out: 14695981039346656037, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in:  map[string]string{"name": "garland, briggs", "fear": "love is not enough"}, | ||||
| 			out: 5799056148416392346, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, scenario := range scenarios { | ||||
| 		actual := LabelsToSignature(scenario.in) | ||||
|  | ||||
| 		if actual != scenario.out { | ||||
| 			t.Errorf("%d. expected %d, got %d", i, scenario.out, actual) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestMetricToFingerprint(t *testing.T) { | ||||
| 	var scenarios = []struct { | ||||
| 		in  LabelSet | ||||
| 		out Fingerprint | ||||
| 	}{ | ||||
| 		{ | ||||
| 			in:  LabelSet{}, | ||||
| 			out: 14695981039346656037, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in:  LabelSet{"name": "garland, briggs", "fear": "love is not enough"}, | ||||
| 			out: 5799056148416392346, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, scenario := range scenarios { | ||||
| 		actual := labelSetToFingerprint(scenario.in) | ||||
|  | ||||
| 		if actual != scenario.out { | ||||
| 			t.Errorf("%d. expected %d, got %d", i, scenario.out, actual) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestMetricToFastFingerprint(t *testing.T) { | ||||
| 	var scenarios = []struct { | ||||
| 		in  LabelSet | ||||
| 		out Fingerprint | ||||
| 	}{ | ||||
| 		{ | ||||
| 			in:  LabelSet{}, | ||||
| 			out: 14695981039346656037, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in:  LabelSet{"name": "garland, briggs", "fear": "love is not enough"}, | ||||
| 			out: 12952432476264840823, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, scenario := range scenarios { | ||||
| 		actual := labelSetToFastFingerprint(scenario.in) | ||||
|  | ||||
| 		if actual != scenario.out { | ||||
| 			t.Errorf("%d. expected %d, got %d", i, scenario.out, actual) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSignatureForLabels(t *testing.T) { | ||||
| 	var scenarios = []struct { | ||||
| 		in     Metric | ||||
| 		labels LabelNames | ||||
| 		out    uint64 | ||||
| 	}{ | ||||
| 		{ | ||||
| 			in:     Metric{}, | ||||
| 			labels: nil, | ||||
| 			out:    14695981039346656037, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in:     Metric{}, | ||||
| 			labels: LabelNames{"empty"}, | ||||
| 			out:    7187873163539638612, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in:     Metric{"name": "garland, briggs", "fear": "love is not enough"}, | ||||
| 			labels: LabelNames{"empty"}, | ||||
| 			out:    7187873163539638612, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in:     Metric{"name": "garland, briggs", "fear": "love is not enough"}, | ||||
| 			labels: LabelNames{"fear", "name"}, | ||||
| 			out:    5799056148416392346, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in:     Metric{"name": "garland, briggs", "fear": "love is not enough", "foo": "bar"}, | ||||
| 			labels: LabelNames{"fear", "name"}, | ||||
| 			out:    5799056148416392346, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in:     Metric{"name": "garland, briggs", "fear": "love is not enough"}, | ||||
| 			labels: LabelNames{}, | ||||
| 			out:    14695981039346656037, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in:     Metric{"name": "garland, briggs", "fear": "love is not enough"}, | ||||
| 			labels: nil, | ||||
| 			out:    14695981039346656037, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, scenario := range scenarios { | ||||
| 		actual := SignatureForLabels(scenario.in, scenario.labels...) | ||||
|  | ||||
| 		if actual != scenario.out { | ||||
| 			t.Errorf("%d. expected %d, got %d", i, scenario.out, actual) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSignatureWithoutLabels(t *testing.T) { | ||||
| 	var scenarios = []struct { | ||||
| 		in     Metric | ||||
| 		labels map[LabelName]struct{} | ||||
| 		out    uint64 | ||||
| 	}{ | ||||
| 		{ | ||||
| 			in:     Metric{}, | ||||
| 			labels: nil, | ||||
| 			out:    14695981039346656037, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in:     Metric{"name": "garland, briggs", "fear": "love is not enough"}, | ||||
| 			labels: map[LabelName]struct{}{"fear": struct{}{}, "name": struct{}{}}, | ||||
| 			out:    14695981039346656037, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in:     Metric{"name": "garland, briggs", "fear": "love is not enough", "foo": "bar"}, | ||||
| 			labels: map[LabelName]struct{}{"foo": struct{}{}}, | ||||
| 			out:    5799056148416392346, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in:     Metric{"name": "garland, briggs", "fear": "love is not enough"}, | ||||
| 			labels: map[LabelName]struct{}{}, | ||||
| 			out:    5799056148416392346, | ||||
| 		}, | ||||
| 		{ | ||||
| 			in:     Metric{"name": "garland, briggs", "fear": "love is not enough"}, | ||||
| 			labels: nil, | ||||
| 			out:    5799056148416392346, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, scenario := range scenarios { | ||||
| 		actual := SignatureWithoutLabels(scenario.in, scenario.labels) | ||||
|  | ||||
| 		if actual != scenario.out { | ||||
| 			t.Errorf("%d. expected %d, got %d", i, scenario.out, actual) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func benchmarkLabelToSignature(b *testing.B, l map[string]string, e uint64) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		if a := LabelsToSignature(l); a != e { | ||||
| 			b.Fatalf("expected signature of %d for %s, got %d", e, l, a) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkLabelToSignatureScalar(b *testing.B) { | ||||
| 	benchmarkLabelToSignature(b, nil, 14695981039346656037) | ||||
| } | ||||
|  | ||||
| func BenchmarkLabelToSignatureSingle(b *testing.B) { | ||||
| 	benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value"}, 5146282821936882169) | ||||
| } | ||||
|  | ||||
| func BenchmarkLabelToSignatureDouble(b *testing.B) { | ||||
| 	benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value", "second-label": "second-label-value"}, 3195800080984914717) | ||||
| } | ||||
|  | ||||
| func BenchmarkLabelToSignatureTriple(b *testing.B) { | ||||
| 	benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 13843036195897128121) | ||||
| } | ||||
|  | ||||
| func benchmarkMetricToFingerprint(b *testing.B, ls LabelSet, e Fingerprint) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		if a := labelSetToFingerprint(ls); a != e { | ||||
| 			b.Fatalf("expected signature of %d for %s, got %d", e, ls, a) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkMetricToFingerprintScalar(b *testing.B) { | ||||
| 	benchmarkMetricToFingerprint(b, nil, 14695981039346656037) | ||||
| } | ||||
|  | ||||
| func BenchmarkMetricToFingerprintSingle(b *testing.B) { | ||||
| 	benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value"}, 5146282821936882169) | ||||
| } | ||||
|  | ||||
| func BenchmarkMetricToFingerprintDouble(b *testing.B) { | ||||
| 	benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value"}, 3195800080984914717) | ||||
| } | ||||
|  | ||||
| func BenchmarkMetricToFingerprintTriple(b *testing.B) { | ||||
| 	benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 13843036195897128121) | ||||
| } | ||||
|  | ||||
| func benchmarkMetricToFastFingerprint(b *testing.B, ls LabelSet, e Fingerprint) { | ||||
| 	for i := 0; i < b.N; i++ { | ||||
| 		if a := labelSetToFastFingerprint(ls); a != e { | ||||
| 			b.Fatalf("expected signature of %d for %s, got %d", e, ls, a) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func BenchmarkMetricToFastFingerprintScalar(b *testing.B) { | ||||
| 	benchmarkMetricToFastFingerprint(b, nil, 14695981039346656037) | ||||
| } | ||||
|  | ||||
| func BenchmarkMetricToFastFingerprintSingle(b *testing.B) { | ||||
| 	benchmarkMetricToFastFingerprint(b, LabelSet{"first-label": "first-label-value"}, 5147259542624943964) | ||||
| } | ||||
|  | ||||
| func BenchmarkMetricToFastFingerprintDouble(b *testing.B) { | ||||
| 	benchmarkMetricToFastFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value"}, 18269973311206963528) | ||||
| } | ||||
|  | ||||
| func BenchmarkMetricToFastFingerprintTriple(b *testing.B) { | ||||
| 	benchmarkMetricToFastFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676) | ||||
| } | ||||
|  | ||||
| func BenchmarkEmptyLabelSignature(b *testing.B) { | ||||
| 	input := []map[string]string{nil, {}} | ||||
|  | ||||
| 	var ms runtime.MemStats | ||||
| 	runtime.ReadMemStats(&ms) | ||||
|  | ||||
| 	alloc := ms.Alloc | ||||
|  | ||||
| 	for _, labels := range input { | ||||
| 		LabelsToSignature(labels) | ||||
| 	} | ||||
|  | ||||
| 	runtime.ReadMemStats(&ms) | ||||
|  | ||||
| 	if got := ms.Alloc; alloc != got { | ||||
| 		b.Fatal("expected LabelsToSignature with empty labels not to perform allocations") | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func benchmarkMetricToFastFingerprintConc(b *testing.B, ls LabelSet, e Fingerprint, concLevel int) { | ||||
| 	var start, end sync.WaitGroup | ||||
| 	start.Add(1) | ||||
| 	end.Add(concLevel) | ||||
|  | ||||
| 	for i := 0; i < concLevel; i++ { | ||||
| 		go func() { | ||||
| 			start.Wait() | ||||
| 			for j := b.N / concLevel; j >= 0; j-- { | ||||
| 				if a := labelSetToFastFingerprint(ls); a != e { | ||||
| 					b.Fatalf("expected signature of %d for %s, got %d", e, ls, a) | ||||
| 				} | ||||
| 			} | ||||
| 			end.Done() | ||||
| 		}() | ||||
| 	} | ||||
| 	b.ResetTimer() | ||||
| 	start.Done() | ||||
| 	end.Wait() | ||||
| } | ||||
|  | ||||
| func BenchmarkMetricToFastFingerprintTripleConc1(b *testing.B) { | ||||
| 	benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 1) | ||||
| } | ||||
|  | ||||
| func BenchmarkMetricToFastFingerprintTripleConc2(b *testing.B) { | ||||
| 	benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 2) | ||||
| } | ||||
|  | ||||
| func BenchmarkMetricToFastFingerprintTripleConc4(b *testing.B) { | ||||
| 	benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 4) | ||||
| } | ||||
|  | ||||
| func BenchmarkMetricToFastFingerprintTripleConc8(b *testing.B) { | ||||
| 	benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 8) | ||||
| } | ||||
							
								
								
									
										228
									
								
								vendor/github.com/prometheus/common/model/silence_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										228
									
								
								vendor/github.com/prometheus/common/model/silence_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,228 +0,0 @@ | ||||
| // Copyright 2015 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 model | ||||
|  | ||||
| import ( | ||||
| 	"strings" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| func TestMatcherValidate(t *testing.T) { | ||||
| 	var cases = []struct { | ||||
| 		matcher *Matcher | ||||
| 		err     string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			matcher: &Matcher{ | ||||
| 				Name:  "name", | ||||
| 				Value: "value", | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			matcher: &Matcher{ | ||||
| 				Name:    "name", | ||||
| 				Value:   "value", | ||||
| 				IsRegex: true, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			matcher: &Matcher{ | ||||
| 				Name:  "name!", | ||||
| 				Value: "value", | ||||
| 			}, | ||||
| 			err: "invalid name", | ||||
| 		}, | ||||
| 		{ | ||||
| 			matcher: &Matcher{ | ||||
| 				Name:  "", | ||||
| 				Value: "value", | ||||
| 			}, | ||||
| 			err: "invalid name", | ||||
| 		}, | ||||
| 		{ | ||||
| 			matcher: &Matcher{ | ||||
| 				Name:  "name", | ||||
| 				Value: "value\xff", | ||||
| 			}, | ||||
| 			err: "invalid value", | ||||
| 		}, | ||||
| 		{ | ||||
| 			matcher: &Matcher{ | ||||
| 				Name:  "name", | ||||
| 				Value: "", | ||||
| 			}, | ||||
| 			err: "invalid value", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, c := range cases { | ||||
| 		err := c.matcher.Validate() | ||||
| 		if err == nil { | ||||
| 			if c.err == "" { | ||||
| 				continue | ||||
| 			} | ||||
| 			t.Errorf("%d. Expected error %q but got none", i, c.err) | ||||
| 			continue | ||||
| 		} | ||||
| 		if c.err == "" && err != nil { | ||||
| 			t.Errorf("%d. Expected no error but got %q", i, err) | ||||
| 			continue | ||||
| 		} | ||||
| 		if !strings.Contains(err.Error(), c.err) { | ||||
| 			t.Errorf("%d. Expected error to contain %q but got %q", i, c.err, err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSilenceValidate(t *testing.T) { | ||||
| 	ts := time.Now() | ||||
|  | ||||
| 	var cases = []struct { | ||||
| 		sil *Silence | ||||
| 		err string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			sil: &Silence{ | ||||
| 				Matchers: []*Matcher{ | ||||
| 					{Name: "name", Value: "value"}, | ||||
| 				}, | ||||
| 				StartsAt:  ts, | ||||
| 				EndsAt:    ts, | ||||
| 				CreatedAt: ts, | ||||
| 				CreatedBy: "name", | ||||
| 				Comment:   "comment", | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			sil: &Silence{ | ||||
| 				Matchers: []*Matcher{ | ||||
| 					{Name: "name", Value: "value"}, | ||||
| 					{Name: "name", Value: "value"}, | ||||
| 					{Name: "name", Value: "value"}, | ||||
| 					{Name: "name", Value: "value", IsRegex: true}, | ||||
| 				}, | ||||
| 				StartsAt:  ts, | ||||
| 				EndsAt:    ts, | ||||
| 				CreatedAt: ts, | ||||
| 				CreatedBy: "name", | ||||
| 				Comment:   "comment", | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			sil: &Silence{ | ||||
| 				Matchers: []*Matcher{ | ||||
| 					{Name: "name", Value: "value"}, | ||||
| 				}, | ||||
| 				StartsAt:  ts, | ||||
| 				EndsAt:    ts.Add(-1 * time.Minute), | ||||
| 				CreatedAt: ts, | ||||
| 				CreatedBy: "name", | ||||
| 				Comment:   "comment", | ||||
| 			}, | ||||
| 			err: "start time must be before end time", | ||||
| 		}, | ||||
| 		{ | ||||
| 			sil: &Silence{ | ||||
| 				Matchers: []*Matcher{ | ||||
| 					{Name: "name", Value: "value"}, | ||||
| 				}, | ||||
| 				StartsAt:  ts, | ||||
| 				CreatedAt: ts, | ||||
| 				CreatedBy: "name", | ||||
| 				Comment:   "comment", | ||||
| 			}, | ||||
| 			err: "end time missing", | ||||
| 		}, | ||||
| 		{ | ||||
| 			sil: &Silence{ | ||||
| 				Matchers: []*Matcher{ | ||||
| 					{Name: "name", Value: "value"}, | ||||
| 				}, | ||||
| 				EndsAt:    ts, | ||||
| 				CreatedAt: ts, | ||||
| 				CreatedBy: "name", | ||||
| 				Comment:   "comment", | ||||
| 			}, | ||||
| 			err: "start time missing", | ||||
| 		}, | ||||
| 		{ | ||||
| 			sil: &Silence{ | ||||
| 				Matchers: []*Matcher{ | ||||
| 					{Name: "!name", Value: "value"}, | ||||
| 				}, | ||||
| 				StartsAt:  ts, | ||||
| 				EndsAt:    ts, | ||||
| 				CreatedAt: ts, | ||||
| 				CreatedBy: "name", | ||||
| 				Comment:   "comment", | ||||
| 			}, | ||||
| 			err: "invalid matcher", | ||||
| 		}, | ||||
| 		{ | ||||
| 			sil: &Silence{ | ||||
| 				Matchers: []*Matcher{ | ||||
| 					{Name: "name", Value: "value"}, | ||||
| 				}, | ||||
| 				StartsAt:  ts, | ||||
| 				EndsAt:    ts, | ||||
| 				CreatedAt: ts, | ||||
| 				CreatedBy: "name", | ||||
| 			}, | ||||
| 			err: "comment missing", | ||||
| 		}, | ||||
| 		{ | ||||
| 			sil: &Silence{ | ||||
| 				Matchers: []*Matcher{ | ||||
| 					{Name: "name", Value: "value"}, | ||||
| 				}, | ||||
| 				StartsAt:  ts, | ||||
| 				EndsAt:    ts, | ||||
| 				CreatedBy: "name", | ||||
| 				Comment:   "comment", | ||||
| 			}, | ||||
| 			err: "creation timestamp missing", | ||||
| 		}, | ||||
| 		{ | ||||
| 			sil: &Silence{ | ||||
| 				Matchers: []*Matcher{ | ||||
| 					{Name: "name", Value: "value"}, | ||||
| 				}, | ||||
| 				StartsAt:  ts, | ||||
| 				EndsAt:    ts, | ||||
| 				CreatedAt: ts, | ||||
| 				Comment:   "comment", | ||||
| 			}, | ||||
| 			err: "creator information missing", | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for i, c := range cases { | ||||
| 		err := c.sil.Validate() | ||||
| 		if err == nil { | ||||
| 			if c.err == "" { | ||||
| 				continue | ||||
| 			} | ||||
| 			t.Errorf("%d. Expected error %q but got none", i, c.err) | ||||
| 			continue | ||||
| 		} | ||||
| 		if c.err == "" && err != nil { | ||||
| 			t.Errorf("%d. Expected no error but got %q", i, err) | ||||
| 			continue | ||||
| 		} | ||||
| 		if !strings.Contains(err.Error(), c.err) { | ||||
| 			t.Errorf("%d. Expected error to contain %q but got %q", i, c.err, err) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										132
									
								
								vendor/github.com/prometheus/common/model/time_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										132
									
								
								vendor/github.com/prometheus/common/model/time_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,132 +0,0 @@ | ||||
| // Copyright 2013 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 model | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| func TestComparators(t *testing.T) { | ||||
| 	t1a := TimeFromUnix(0) | ||||
| 	t1b := TimeFromUnix(0) | ||||
| 	t2 := TimeFromUnix(2*second - 1) | ||||
|  | ||||
| 	if !t1a.Equal(t1b) { | ||||
| 		t.Fatalf("Expected %s to be equal to %s", t1a, t1b) | ||||
| 	} | ||||
| 	if t1a.Equal(t2) { | ||||
| 		t.Fatalf("Expected %s to not be equal to %s", t1a, t2) | ||||
| 	} | ||||
|  | ||||
| 	if !t1a.Before(t2) { | ||||
| 		t.Fatalf("Expected %s to be before %s", t1a, t2) | ||||
| 	} | ||||
| 	if t1a.Before(t1b) { | ||||
| 		t.Fatalf("Expected %s to not be before %s", t1a, t1b) | ||||
| 	} | ||||
|  | ||||
| 	if !t2.After(t1a) { | ||||
| 		t.Fatalf("Expected %s to be after %s", t2, t1a) | ||||
| 	} | ||||
| 	if t1b.After(t1a) { | ||||
| 		t.Fatalf("Expected %s to not be after %s", t1b, t1a) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestTimeConversions(t *testing.T) { | ||||
| 	unixSecs := int64(1136239445) | ||||
| 	unixNsecs := int64(123456789) | ||||
| 	unixNano := unixSecs*1e9 + unixNsecs | ||||
|  | ||||
| 	t1 := time.Unix(unixSecs, unixNsecs-unixNsecs%nanosPerTick) | ||||
| 	t2 := time.Unix(unixSecs, unixNsecs) | ||||
|  | ||||
| 	ts := TimeFromUnixNano(unixNano) | ||||
| 	if !ts.Time().Equal(t1) { | ||||
| 		t.Fatalf("Expected %s, got %s", t1, ts.Time()) | ||||
| 	} | ||||
|  | ||||
| 	// Test available precision. | ||||
| 	ts = TimeFromUnixNano(t2.UnixNano()) | ||||
| 	if !ts.Time().Equal(t1) { | ||||
| 		t.Fatalf("Expected %s, got %s", t1, ts.Time()) | ||||
| 	} | ||||
|  | ||||
| 	if ts.UnixNano() != unixNano-unixNano%nanosPerTick { | ||||
| 		t.Fatalf("Expected %d, got %d", unixNano, ts.UnixNano()) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestDuration(t *testing.T) { | ||||
| 	duration := time.Second + time.Minute + time.Hour | ||||
| 	goTime := time.Unix(1136239445, 0) | ||||
|  | ||||
| 	ts := TimeFromUnix(goTime.Unix()) | ||||
| 	if !goTime.Add(duration).Equal(ts.Add(duration).Time()) { | ||||
| 		t.Fatalf("Expected %s to be equal to %s", goTime.Add(duration), ts.Add(duration)) | ||||
| 	} | ||||
|  | ||||
| 	earlier := ts.Add(-duration) | ||||
| 	delta := ts.Sub(earlier) | ||||
| 	if delta != duration { | ||||
| 		t.Fatalf("Expected %s to be equal to %s", delta, duration) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestParseDuration(t *testing.T) { | ||||
| 	var cases = []struct { | ||||
| 		in  string | ||||
| 		out time.Duration | ||||
| 	}{ | ||||
| 		{ | ||||
| 			in:  "0s", | ||||
| 			out: 0, | ||||
| 		}, { | ||||
| 			in:  "324ms", | ||||
| 			out: 324 * time.Millisecond, | ||||
| 		}, { | ||||
| 			in:  "3s", | ||||
| 			out: 3 * time.Second, | ||||
| 		}, { | ||||
| 			in:  "5m", | ||||
| 			out: 5 * time.Minute, | ||||
| 		}, { | ||||
| 			in:  "1h", | ||||
| 			out: time.Hour, | ||||
| 		}, { | ||||
| 			in:  "4d", | ||||
| 			out: 4 * 24 * time.Hour, | ||||
| 		}, { | ||||
| 			in:  "3w", | ||||
| 			out: 3 * 7 * 24 * time.Hour, | ||||
| 		}, { | ||||
| 			in:  "10y", | ||||
| 			out: 10 * 365 * 24 * time.Hour, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, c := range cases { | ||||
| 		d, err := ParseDuration(c.in) | ||||
| 		if err != nil { | ||||
| 			t.Errorf("Unexpected error on input %q", c.in) | ||||
| 		} | ||||
| 		if time.Duration(d) != c.out { | ||||
| 			t.Errorf("Expected %v but got %v", c.out, d) | ||||
| 		} | ||||
| 		if d.String() != c.in { | ||||
| 			t.Errorf("Expected duration string %q but got %q", c.in, d.String()) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										468
									
								
								vendor/github.com/prometheus/common/model/value_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										468
									
								
								vendor/github.com/prometheus/common/model/value_test.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,468 +0,0 @@ | ||||
| // Copyright 2013 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 model | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"math" | ||||
| 	"reflect" | ||||
| 	"sort" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestEqualValues(t *testing.T) { | ||||
| 	tests := map[string]struct { | ||||
| 		in1, in2 SampleValue | ||||
| 		want     bool | ||||
| 	}{ | ||||
| 		"equal floats": { | ||||
| 			in1:  3.14, | ||||
| 			in2:  3.14, | ||||
| 			want: true, | ||||
| 		}, | ||||
| 		"unequal floats": { | ||||
| 			in1:  3.14, | ||||
| 			in2:  3.1415, | ||||
| 			want: false, | ||||
| 		}, | ||||
| 		"positive inifinities": { | ||||
| 			in1:  SampleValue(math.Inf(+1)), | ||||
| 			in2:  SampleValue(math.Inf(+1)), | ||||
| 			want: true, | ||||
| 		}, | ||||
| 		"negative inifinities": { | ||||
| 			in1:  SampleValue(math.Inf(-1)), | ||||
| 			in2:  SampleValue(math.Inf(-1)), | ||||
| 			want: true, | ||||
| 		}, | ||||
| 		"different inifinities": { | ||||
| 			in1:  SampleValue(math.Inf(+1)), | ||||
| 			in2:  SampleValue(math.Inf(-1)), | ||||
| 			want: false, | ||||
| 		}, | ||||
| 		"number and infinity": { | ||||
| 			in1:  42, | ||||
| 			in2:  SampleValue(math.Inf(+1)), | ||||
| 			want: false, | ||||
| 		}, | ||||
| 		"number and NaN": { | ||||
| 			in1:  42, | ||||
| 			in2:  SampleValue(math.NaN()), | ||||
| 			want: false, | ||||
| 		}, | ||||
| 		"NaNs": { | ||||
| 			in1:  SampleValue(math.NaN()), | ||||
| 			in2:  SampleValue(math.NaN()), | ||||
| 			want: true, // !!! | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for name, test := range tests { | ||||
| 		got := test.in1.Equal(test.in2) | ||||
| 		if got != test.want { | ||||
| 			t.Errorf("Comparing %s, %f and %f: got %t, want %t", name, test.in1, test.in2, got, test.want) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestEqualSamples(t *testing.T) { | ||||
| 	testSample := &Sample{} | ||||
|  | ||||
| 	tests := map[string]struct { | ||||
| 		in1, in2 *Sample | ||||
| 		want     bool | ||||
| 	}{ | ||||
| 		"equal pointers": { | ||||
| 			in1:  testSample, | ||||
| 			in2:  testSample, | ||||
| 			want: true, | ||||
| 		}, | ||||
| 		"different metrics": { | ||||
| 			in1:  &Sample{Metric: Metric{"foo": "bar"}}, | ||||
| 			in2:  &Sample{Metric: Metric{"foo": "biz"}}, | ||||
| 			want: false, | ||||
| 		}, | ||||
| 		"different timestamp": { | ||||
| 			in1:  &Sample{Timestamp: 0}, | ||||
| 			in2:  &Sample{Timestamp: 1}, | ||||
| 			want: false, | ||||
| 		}, | ||||
| 		"different value": { | ||||
| 			in1:  &Sample{Value: 0}, | ||||
| 			in2:  &Sample{Value: 1}, | ||||
| 			want: false, | ||||
| 		}, | ||||
| 		"equal samples": { | ||||
| 			in1: &Sample{ | ||||
| 				Metric:    Metric{"foo": "bar"}, | ||||
| 				Timestamp: 0, | ||||
| 				Value:     1, | ||||
| 			}, | ||||
| 			in2: &Sample{ | ||||
| 				Metric:    Metric{"foo": "bar"}, | ||||
| 				Timestamp: 0, | ||||
| 				Value:     1, | ||||
| 			}, | ||||
| 			want: true, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for name, test := range tests { | ||||
| 		got := test.in1.Equal(test.in2) | ||||
| 		if got != test.want { | ||||
| 			t.Errorf("Comparing %s, %v and %v: got %t, want %t", name, test.in1, test.in2, got, test.want) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| func TestSamplePairJSON(t *testing.T) { | ||||
| 	input := []struct { | ||||
| 		plain string | ||||
| 		value SamplePair | ||||
| 	}{ | ||||
| 		{ | ||||
| 			plain: `[1234.567,"123.1"]`, | ||||
| 			value: SamplePair{ | ||||
| 				Value:     123.1, | ||||
| 				Timestamp: 1234567, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, test := range input { | ||||
| 		b, err := json.Marshal(test.value) | ||||
| 		if err != nil { | ||||
| 			t.Error(err) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if string(b) != test.plain { | ||||
| 			t.Errorf("encoding error: expected %q, got %q", test.plain, b) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		var sp SamplePair | ||||
| 		err = json.Unmarshal(b, &sp) | ||||
| 		if err != nil { | ||||
| 			t.Error(err) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if sp != test.value { | ||||
| 			t.Errorf("decoding error: expected %v, got %v", test.value, sp) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestSampleJSON(t *testing.T) { | ||||
| 	input := []struct { | ||||
| 		plain string | ||||
| 		value Sample | ||||
| 	}{ | ||||
| 		{ | ||||
| 			plain: `{"metric":{"__name__":"test_metric"},"value":[1234.567,"123.1"]}`, | ||||
| 			value: Sample{ | ||||
| 				Metric: Metric{ | ||||
| 					MetricNameLabel: "test_metric", | ||||
| 				}, | ||||
| 				Value:     123.1, | ||||
| 				Timestamp: 1234567, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, test := range input { | ||||
| 		b, err := json.Marshal(test.value) | ||||
| 		if err != nil { | ||||
| 			t.Error(err) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if string(b) != test.plain { | ||||
| 			t.Errorf("encoding error: expected %q, got %q", test.plain, b) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		var sv Sample | ||||
| 		err = json.Unmarshal(b, &sv) | ||||
| 		if err != nil { | ||||
| 			t.Error(err) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if !reflect.DeepEqual(sv, test.value) { | ||||
| 			t.Errorf("decoding error: expected %v, got %v", test.value, sv) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestVectorJSON(t *testing.T) { | ||||
| 	input := []struct { | ||||
| 		plain string | ||||
| 		value Vector | ||||
| 	}{ | ||||
| 		{ | ||||
| 			plain: `[]`, | ||||
| 			value: Vector{}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			plain: `[{"metric":{"__name__":"test_metric"},"value":[1234.567,"123.1"]}]`, | ||||
| 			value: Vector{&Sample{ | ||||
| 				Metric: Metric{ | ||||
| 					MetricNameLabel: "test_metric", | ||||
| 				}, | ||||
| 				Value:     123.1, | ||||
| 				Timestamp: 1234567, | ||||
| 			}}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			plain: `[{"metric":{"__name__":"test_metric"},"value":[1234.567,"123.1"]},{"metric":{"foo":"bar"},"value":[1.234,"+Inf"]}]`, | ||||
| 			value: Vector{ | ||||
| 				&Sample{ | ||||
| 					Metric: Metric{ | ||||
| 						MetricNameLabel: "test_metric", | ||||
| 					}, | ||||
| 					Value:     123.1, | ||||
| 					Timestamp: 1234567, | ||||
| 				}, | ||||
| 				&Sample{ | ||||
| 					Metric: Metric{ | ||||
| 						"foo": "bar", | ||||
| 					}, | ||||
| 					Value:     SampleValue(math.Inf(1)), | ||||
| 					Timestamp: 1234, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, test := range input { | ||||
| 		b, err := json.Marshal(test.value) | ||||
| 		if err != nil { | ||||
| 			t.Error(err) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if string(b) != test.plain { | ||||
| 			t.Errorf("encoding error: expected %q, got %q", test.plain, b) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		var vec Vector | ||||
| 		err = json.Unmarshal(b, &vec) | ||||
| 		if err != nil { | ||||
| 			t.Error(err) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if !reflect.DeepEqual(vec, test.value) { | ||||
| 			t.Errorf("decoding error: expected %v, got %v", test.value, vec) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestScalarJSON(t *testing.T) { | ||||
| 	input := []struct { | ||||
| 		plain string | ||||
| 		value Scalar | ||||
| 	}{ | ||||
| 		{ | ||||
| 			plain: `[123.456,"456"]`, | ||||
| 			value: Scalar{ | ||||
| 				Timestamp: 123456, | ||||
| 				Value:     456, | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			plain: `[123123.456,"+Inf"]`, | ||||
| 			value: Scalar{ | ||||
| 				Timestamp: 123123456, | ||||
| 				Value:     SampleValue(math.Inf(1)), | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			plain: `[123123.456,"-Inf"]`, | ||||
| 			value: Scalar{ | ||||
| 				Timestamp: 123123456, | ||||
| 				Value:     SampleValue(math.Inf(-1)), | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, test := range input { | ||||
| 		b, err := json.Marshal(test.value) | ||||
| 		if err != nil { | ||||
| 			t.Error(err) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if string(b) != test.plain { | ||||
| 			t.Errorf("encoding error: expected %q, got %q", test.plain, b) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		var sv Scalar | ||||
| 		err = json.Unmarshal(b, &sv) | ||||
| 		if err != nil { | ||||
| 			t.Error(err) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if sv != test.value { | ||||
| 			t.Errorf("decoding error: expected %v, got %v", test.value, sv) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestStringJSON(t *testing.T) { | ||||
| 	input := []struct { | ||||
| 		plain string | ||||
| 		value String | ||||
| 	}{ | ||||
| 		{ | ||||
| 			plain: `[123.456,"test"]`, | ||||
| 			value: String{ | ||||
| 				Timestamp: 123456, | ||||
| 				Value:     "test", | ||||
| 			}, | ||||
| 		}, | ||||
| 		{ | ||||
| 			plain: `[123123.456,"台北"]`, | ||||
| 			value: String{ | ||||
| 				Timestamp: 123123456, | ||||
| 				Value:     "台北", | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	for _, test := range input { | ||||
| 		b, err := json.Marshal(test.value) | ||||
| 		if err != nil { | ||||
| 			t.Error(err) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if string(b) != test.plain { | ||||
| 			t.Errorf("encoding error: expected %q, got %q", test.plain, b) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		var sv String | ||||
| 		err = json.Unmarshal(b, &sv) | ||||
| 		if err != nil { | ||||
| 			t.Error(err) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if sv != test.value { | ||||
| 			t.Errorf("decoding error: expected %v, got %v", test.value, sv) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestVectorSort(t *testing.T) { | ||||
| 	input := Vector{ | ||||
| 		&Sample{ | ||||
| 			Metric: Metric{ | ||||
| 				MetricNameLabel: "A", | ||||
| 			}, | ||||
| 			Timestamp: 1, | ||||
| 		}, | ||||
| 		&Sample{ | ||||
| 			Metric: Metric{ | ||||
| 				MetricNameLabel: "A", | ||||
| 			}, | ||||
| 			Timestamp: 2, | ||||
| 		}, | ||||
| 		&Sample{ | ||||
| 			Metric: Metric{ | ||||
| 				MetricNameLabel: "C", | ||||
| 			}, | ||||
| 			Timestamp: 1, | ||||
| 		}, | ||||
| 		&Sample{ | ||||
| 			Metric: Metric{ | ||||
| 				MetricNameLabel: "C", | ||||
| 			}, | ||||
| 			Timestamp: 2, | ||||
| 		}, | ||||
| 		&Sample{ | ||||
| 			Metric: Metric{ | ||||
| 				MetricNameLabel: "B", | ||||
| 			}, | ||||
| 			Timestamp: 1, | ||||
| 		}, | ||||
| 		&Sample{ | ||||
| 			Metric: Metric{ | ||||
| 				MetricNameLabel: "B", | ||||
| 			}, | ||||
| 			Timestamp: 2, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	expected := Vector{ | ||||
| 		&Sample{ | ||||
| 			Metric: Metric{ | ||||
| 				MetricNameLabel: "A", | ||||
| 			}, | ||||
| 			Timestamp: 1, | ||||
| 		}, | ||||
| 		&Sample{ | ||||
| 			Metric: Metric{ | ||||
| 				MetricNameLabel: "A", | ||||
| 			}, | ||||
| 			Timestamp: 2, | ||||
| 		}, | ||||
| 		&Sample{ | ||||
| 			Metric: Metric{ | ||||
| 				MetricNameLabel: "B", | ||||
| 			}, | ||||
| 			Timestamp: 1, | ||||
| 		}, | ||||
| 		&Sample{ | ||||
| 			Metric: Metric{ | ||||
| 				MetricNameLabel: "B", | ||||
| 			}, | ||||
| 			Timestamp: 2, | ||||
| 		}, | ||||
| 		&Sample{ | ||||
| 			Metric: Metric{ | ||||
| 				MetricNameLabel: "C", | ||||
| 			}, | ||||
| 			Timestamp: 1, | ||||
| 		}, | ||||
| 		&Sample{ | ||||
| 			Metric: Metric{ | ||||
| 				MetricNameLabel: "C", | ||||
| 			}, | ||||
| 			Timestamp: 2, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	sort.Sort(input) | ||||
|  | ||||
| 	for i, actual := range input { | ||||
| 		actualFp := actual.Metric.Fingerprint() | ||||
| 		expectedFp := expected[i].Metric.Fingerprint() | ||||
|  | ||||
| 		if actualFp != expectedFp { | ||||
| 			t.Fatalf("%d. Incorrect fingerprint. Got %s; want %s", i, actualFp.String(), expectedFp.String()) | ||||
| 		} | ||||
|  | ||||
| 		if actual.Timestamp != expected[i].Timestamp { | ||||
| 			t.Fatalf("%d. Incorrect timestamp. Got %s; want %s", i, actual.Timestamp, expected[i].Timestamp) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
		Reference in New Issue
	
	Block a user