1// Copyright 2018 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package expfmt
15
16import (
17	"bytes"
18	"github.com/golang/protobuf/proto"
19	dto "github.com/prometheus/client_model/go"
20	"net/http"
21	"testing"
22)
23
24func TestNegotiate(t *testing.T) {
25	acceptValuePrefix := "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily"
26	tests := []struct {
27		name              string
28		acceptHeaderValue string
29		expectedFmt       string
30	}{
31		{
32			name:              "delimited format",
33			acceptHeaderValue: acceptValuePrefix + ";encoding=delimited",
34			expectedFmt:       string(FmtProtoDelim),
35		},
36		{
37			name:              "text format",
38			acceptHeaderValue: acceptValuePrefix + ";encoding=text",
39			expectedFmt:       string(FmtProtoText),
40		},
41		{
42			name:              "compact text format",
43			acceptHeaderValue: acceptValuePrefix + ";encoding=compact-text",
44			expectedFmt:       string(FmtProtoCompact),
45		},
46		{
47			name:              "plain text format",
48			acceptHeaderValue: "text/plain;version=0.0.4",
49			expectedFmt:       string(FmtText),
50		},
51	}
52
53	for _, test := range tests {
54		t.Run(test.name, func(t *testing.T) {
55			h := http.Header{}
56			h.Add(hdrAccept, test.acceptHeaderValue)
57			actualFmt := string(Negotiate(h))
58			if actualFmt != test.expectedFmt {
59				t.Errorf("expected Negotiate to return format %s, but got %s instead", test.expectedFmt, actualFmt)
60			}
61		})
62	}
63}
64
65func TestEncode(t *testing.T) {
66	var buff bytes.Buffer
67	delimEncoder := NewEncoder(&buff, FmtProtoDelim)
68	metric := &dto.MetricFamily{
69		Name: proto.String("foo_metric"),
70		Type: dto.MetricType_UNTYPED.Enum(),
71		Metric: []*dto.Metric{
72			{
73				Untyped: &dto.Untyped{
74					Value: proto.Float64(1.234),
75				},
76			},
77		},
78	}
79
80	err := delimEncoder.Encode(metric)
81	if err != nil {
82		t.Errorf("unexpected error during encode: %s", err.Error())
83	}
84
85	out := buff.Bytes()
86	if len(out) == 0 {
87		t.Errorf("expected the output bytes buffer to be non-empty")
88	}
89
90	buff.Reset()
91
92	compactEncoder := NewEncoder(&buff, FmtProtoCompact)
93	err = compactEncoder.Encode(metric)
94	if err != nil {
95		t.Errorf("unexpected error during encode: %s", err.Error())
96	}
97
98	out = buff.Bytes()
99	if len(out) == 0 {
100		t.Errorf("expected the output bytes buffer to be non-empty")
101	}
102
103	buff.Reset()
104
105	protoTextEncoder := NewEncoder(&buff, FmtProtoText)
106	err = protoTextEncoder.Encode(metric)
107	if err != nil {
108		t.Errorf("unexpected error during encode: %s", err.Error())
109	}
110
111	out = buff.Bytes()
112	if len(out) == 0 {
113		t.Errorf("expected the output bytes buffer to be non-empty")
114	}
115
116	buff.Reset()
117
118	textEncoder := NewEncoder(&buff, FmtText)
119	err = textEncoder.Encode(metric)
120	if err != nil {
121		t.Errorf("unexpected error during encode: %s", err.Error())
122	}
123
124	out = buff.Bytes()
125	if len(out) == 0 {
126		t.Errorf("expected the output bytes buffer to be non-empty")
127	}
128
129	expected := "# TYPE foo_metric untyped\n" +
130		"foo_metric 1.234\n"
131
132	if string(out) != expected {
133		t.Errorf("expected TextEncoder to return %s, but got %s instead", expected, string(out))
134	}
135}
136