mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-10-17 10:09:05 +02:00
267 lines
6.6 KiB
Go
267 lines
6.6 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
// Copyright 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.
|
|
|
|
//go:build windows
|
|
|
|
package textfile
|
|
|
|
import (
|
|
"io"
|
|
"log/slog"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
dto "github.com/prometheus/client_model/go"
|
|
)
|
|
|
|
func TestCRFilter(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
sr := strings.NewReader("line 1\r\nline 2")
|
|
cr := carriageReturnFilteringReader{r: sr}
|
|
|
|
b, err := io.ReadAll(cr)
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
if string(b) != "line 1\nline 2" {
|
|
t.Errorf("Unexpected output %q", b)
|
|
}
|
|
}
|
|
|
|
func TestScrapeFileBOM(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, tc := range []struct {
|
|
name string
|
|
prefix string
|
|
err string
|
|
}{
|
|
{name: "plain UTF-8"},
|
|
{name: "UTF-8 BOM", prefix: "\xef\xbb\xbf"},
|
|
{name: "UTF-16 BE", prefix: "\xfe\xff", err: "UTF16BigEndian"},
|
|
{name: "UTF-16 LE", prefix: "\xff\xfe", err: "UTF16LittleEndian"},
|
|
{name: "UTF-32 BE", prefix: "\x00\x00\xfe\xff", err: "UTF32BigEndian"},
|
|
{name: "UTF-32 LE", prefix: "\xff\xfe\x00\x00", err: "UTF32LittleEndian"},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
path := filepath.Join(t.TempDir(), "metric.prom")
|
|
content := tc.prefix + "# TYPE metric gauge\r\nmetric 1\r\n"
|
|
|
|
if err := os.WriteFile(path, []byte(content), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
families, err := scrapeFile(path, slog.New(slog.DiscardHandler))
|
|
if tc.err != "" {
|
|
if err == nil || err.Error() != tc.err {
|
|
t.Fatalf("got error %v, want %s", err, tc.err)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if len(families) != 1 || families[0].GetName() != "metric" {
|
|
t.Fatalf("unexpected metric families: %v", families)
|
|
}
|
|
|
|
metrics := families[0].GetMetric()
|
|
if len(metrics) != 1 || metrics[0].GetGauge().GetValue() != 1 {
|
|
t.Errorf("unexpected metrics: %v", metrics)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDuplicateMetricEntry(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
metric_name := "windows_sometest"
|
|
metric_help := "This is a Test."
|
|
metric_type := dto.MetricType_GAUGE
|
|
|
|
gauge_value := 1.0
|
|
|
|
gauge := dto.Gauge{
|
|
Value: &gauge_value,
|
|
}
|
|
|
|
label1_name := "display_name"
|
|
label1_value := "foobar"
|
|
|
|
label1 := dto.LabelPair{
|
|
Name: &label1_name,
|
|
Value: &label1_value,
|
|
}
|
|
|
|
label2_name := "display_version"
|
|
label2_value := "13.4.0"
|
|
|
|
label2 := dto.LabelPair{
|
|
Name: &label2_name,
|
|
Value: &label2_value,
|
|
}
|
|
|
|
metric1 := dto.Metric{
|
|
Label: []*dto.LabelPair{&label1, &label2},
|
|
Gauge: &gauge,
|
|
}
|
|
|
|
metric2 := dto.Metric{
|
|
Label: []*dto.LabelPair{&label1, &label2},
|
|
Gauge: &gauge,
|
|
}
|
|
|
|
duplicate := dto.MetricFamily{
|
|
Name: &metric_name,
|
|
Help: &metric_help,
|
|
Type: &metric_type,
|
|
Metric: []*dto.Metric{&metric1, &metric2},
|
|
}
|
|
|
|
duplicateFamily := make([]*dto.MetricFamily, 0, 1)
|
|
|
|
duplicateFamily = append(duplicateFamily, &duplicate)
|
|
|
|
// Ensure detection for duplicate metrics
|
|
if !duplicateMetricEntry(duplicateFamily) {
|
|
t.Errorf("Duplicate not found in duplicateFamily")
|
|
}
|
|
|
|
label3_name := "test"
|
|
label3_value := "1.0"
|
|
|
|
label3 := dto.LabelPair{
|
|
Name: &label3_name,
|
|
Value: &label3_value,
|
|
}
|
|
metric3 := dto.Metric{
|
|
Label: []*dto.LabelPair{&label1, &label2, &label3},
|
|
Gauge: &gauge,
|
|
}
|
|
|
|
differentLabels := dto.MetricFamily{
|
|
Name: &metric_name,
|
|
Help: &metric_help,
|
|
Type: &metric_type,
|
|
Metric: []*dto.Metric{&metric1, &metric3},
|
|
}
|
|
|
|
duplicateFamily = make([]*dto.MetricFamily, 0, 1)
|
|
duplicateFamily = append(duplicateFamily, &differentLabels)
|
|
|
|
// Additional label on second metric should not be cause for duplicate detection
|
|
if duplicateMetricEntry(duplicateFamily) {
|
|
t.Errorf("Unexpected duplicate found in differentLabels")
|
|
}
|
|
|
|
label4_value := "2.0"
|
|
|
|
label4 := dto.LabelPair{
|
|
Name: &label3_name,
|
|
Value: &label4_value,
|
|
}
|
|
metric4 := dto.Metric{
|
|
Label: []*dto.LabelPair{&label1, &label2, &label4},
|
|
Gauge: &gauge,
|
|
}
|
|
|
|
differentValues := dto.MetricFamily{
|
|
Name: &metric_name,
|
|
Help: &metric_help,
|
|
Type: &metric_type,
|
|
Metric: []*dto.Metric{&metric3, &metric4},
|
|
}
|
|
duplicateFamily = make([]*dto.MetricFamily, 0, 1)
|
|
duplicateFamily = append(duplicateFamily, &differentValues)
|
|
|
|
// Additional label with different values metric should not be cause for duplicate detection
|
|
if duplicateMetricEntry(duplicateFamily) {
|
|
t.Errorf("Unexpected duplicate found in differentValues")
|
|
}
|
|
}
|
|
|
|
func TestDuplicateMetricEntryAnyPosition(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
type pair [2]string
|
|
|
|
metric := func(labels ...pair) *dto.Metric {
|
|
m := &dto.Metric{}
|
|
|
|
for _, label := range labels {
|
|
m.Label = append(m.Label, &dto.LabelPair{Name: &label[0], Value: &label[1]})
|
|
}
|
|
|
|
return m
|
|
}
|
|
|
|
family := func(name string, metrics ...*dto.Metric) *dto.MetricFamily {
|
|
return &dto.MetricFamily{Name: &name, Metric: metrics}
|
|
}
|
|
|
|
for _, tc := range []struct {
|
|
name string
|
|
families []*dto.MetricFamily
|
|
duplicate bool
|
|
}{
|
|
{
|
|
name: "duplicate is not adjacent",
|
|
families: []*dto.MetricFamily{family("m", metric(pair{"a", "1"}), metric(pair{"a", "2"}), metric(pair{"a", "1"}))},
|
|
duplicate: true,
|
|
},
|
|
{
|
|
name: "duplicate in another family of the same name",
|
|
families: []*dto.MetricFamily{family("m", metric(pair{"a", "1"}), metric(pair{"a", "2"})), family("m", metric(pair{"a", "1"}))},
|
|
duplicate: true,
|
|
},
|
|
{
|
|
name: "different label order",
|
|
families: []*dto.MetricFamily{family("m", metric(pair{"a", "1"}, pair{"b", "2"}), metric(pair{"b", "2"}, pair{"a", "1"}))},
|
|
duplicate: true,
|
|
},
|
|
{
|
|
name: "empty label value is absent",
|
|
families: []*dto.MetricFamily{family("m", metric(pair{"a", "1"}), metric(pair{"a", "1"}, pair{"b", ""}))},
|
|
duplicate: true,
|
|
},
|
|
{
|
|
name: "same labels in different metrics",
|
|
families: []*dto.MetricFamily{family("m", metric(pair{"a", "1"})), family("n", metric(pair{"a", "1"}))},
|
|
},
|
|
{
|
|
name: "label value shifted between labels",
|
|
families: []*dto.MetricFamily{family("m", metric(pair{"a", "1"}, pair{"b", "2"}), metric(pair{"a", "12"}, pair{"b", ""}))},
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if got := duplicateMetricEntry(tc.families); got != tc.duplicate {
|
|
t.Errorf("duplicateMetricEntry() = %t, want %t", got, tc.duplicate)
|
|
}
|
|
})
|
|
}
|
|
}
|