Marshal Matcher to JSON for API v1 compatibility

Signed-off-by: Kiril Vladimirov <kiril@vladimiroff.org>
This commit is contained in:
Kiril Vladimirov 2021-01-22 16:29:36 +02:00
parent 97e0c754c0
commit f85651f2c4
2 changed files with 109 additions and 1 deletions

View File

@ -15,6 +15,7 @@ package labels
import ( import (
"bytes" "bytes"
"encoding/json"
"fmt" "fmt"
"regexp" "regexp"
"strings" "strings"
@ -91,6 +92,49 @@ func (m *Matcher) Matches(s string) bool {
panic("labels.Matcher.Matches: invalid match type") panic("labels.Matcher.Matches: invalid match type")
} }
type apiV1Matcher struct {
Name string `json:"name"`
Value string `json:"value"`
IsRegex bool `json:"isRegex"`
IsEqual bool `json:"isEqual"`
}
// MarshalJSON retains backwards compatibility with types.Matcher for the v1 API.
func (m Matcher) MarshalJSON() ([]byte, error) {
return json.Marshal(apiV1Matcher{
Name: m.Name,
Value: m.Value,
IsRegex: m.Type == MatchRegexp || m.Type == MatchNotRegexp,
IsEqual: m.Type == MatchRegexp || m.Type == MatchEqual,
})
}
func (m *Matcher) UnmarshalJSON(data []byte) error {
var v1m apiV1Matcher
if err := json.Unmarshal(data, &v1m); err != nil {
return err
}
var t MatchType
switch {
case v1m.IsEqual && !v1m.IsRegex:
t = MatchEqual
case !v1m.IsEqual && !v1m.IsRegex:
t = MatchNotEqual
case v1m.IsEqual && v1m.IsRegex:
t = MatchRegexp
case !v1m.IsEqual && v1m.IsRegex:
t = MatchNotRegexp
}
matcher, err := NewMatcher(t, v1m.Name, v1m.Value)
if err != nil {
return err
}
*m = *matcher
return nil
}
// openMetricsEscape is similar to the usual string escaping, but more // openMetricsEscape is similar to the usual string escaping, but more
// restricted. It merely replaces a new-line character with '\n', a double-quote // restricted. It merely replaces a new-line character with '\n', a double-quote
// character with '\"', and a backslash with '\\', which is the escaping used by // character with '\"', and a backslash with '\\', which is the escaping used by

View File

@ -13,7 +13,10 @@
package labels package labels
import "testing" import (
"encoding/json"
"testing"
)
func mustNewMatcher(t *testing.T, mType MatchType, value string) *Matcher { func mustNewMatcher(t *testing.T, mType MatchType, value string) *Matcher {
m, err := NewMatcher(mType, "", value) m, err := NewMatcher(mType, "", value)
@ -191,3 +194,64 @@ line`,
} }
} }
} }
func TestMatcherJSON(t *testing.T) {
tests := []struct {
name string
op MatchType
value string
want string
}{
{
name: `foo`,
op: MatchEqual,
value: `bar`,
want: `{"name":"foo","value":"bar","isRegex":false,"isEqual":true}`,
},
{
name: `foo`,
op: MatchNotEqual,
value: `bar`,
want: `{"name":"foo","value":"bar","isRegex":false,"isEqual":false}`,
},
{
name: `foo`,
op: MatchRegexp,
value: `bar`,
want: `{"name":"foo","value":"bar","isRegex":true,"isEqual":true}`,
},
{
name: `foo`,
op: MatchNotRegexp,
value: `bar`,
want: `{"name":"foo","value":"bar","isRegex":true,"isEqual":false}`,
},
}
cmp := func(m1, m2 Matcher) bool {
return m1.Name == m2.Name && m1.Value == m2.Value && m1.Type == m2.Type
}
for _, test := range tests {
m, err := NewMatcher(test.op, test.name, test.value)
if err != nil {
t.Fatal(err)
}
b, err := json.Marshal(m)
if err != nil {
t.Fatal(err)
}
if got := string(b); got != test.want {
t.Errorf("Unexpected JSON representation of matcher:\nwant:\t%v\ngot:\t%v", test.want, got)
}
var m2 Matcher
if err := json.Unmarshal(b, &m2); err != nil {
t.Fatal(err)
}
if !cmp(*m, m2) {
t.Errorf("Doing Marshal and Unmarshal seems to be losing data; before %#v, after %#v", m, m2)
}
}
}