mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
304 lines
9.2 KiB
Go
304 lines
9.2 KiB
Go
package models
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
type testObj struct {
|
|
Md Annotations `json:"annotations,omitempty"`
|
|
}
|
|
|
|
type myJson struct {
|
|
Foo string `json:"foo,omitempty"`
|
|
Bar string `json:"bar,omitempty"`
|
|
}
|
|
|
|
func (m Annotations) withRawKey(key string, val string) Annotations {
|
|
newMd := make(Annotations)
|
|
for k, v := range m {
|
|
newMd[k] = v
|
|
}
|
|
|
|
v := annotationValue([]byte(val))
|
|
newMd[key] = &v
|
|
return newMd
|
|
}
|
|
|
|
func mustParseMd(t *testing.T, md string) Annotations {
|
|
mdObj := make(Annotations)
|
|
|
|
err := json.Unmarshal([]byte(md), &mdObj)
|
|
if err != nil {
|
|
t.Fatalf("Failed to parse must-parse value %s %v", md, err)
|
|
}
|
|
return mdObj
|
|
}
|
|
|
|
func TestAnnotationsEqual(t *testing.T) {
|
|
annWithVal, _ := EmptyAnnotations().With("foo", "Bar")
|
|
|
|
tcs := []struct {
|
|
a Annotations
|
|
b Annotations
|
|
equals bool
|
|
}{
|
|
{EmptyAnnotations(), EmptyAnnotations(), true},
|
|
{annWithVal, EmptyAnnotations(), false},
|
|
{annWithVal, annWithVal, true},
|
|
{EmptyAnnotations().withRawKey("v1", `"a"`), EmptyAnnotations().withRawKey("v1", `"b"`), false},
|
|
{EmptyAnnotations().withRawKey("v1", `"a"`), EmptyAnnotations().withRawKey("v2", `"a"`), false},
|
|
|
|
{annWithVal.Without("foo"), EmptyAnnotations(), true},
|
|
{mustParseMd(t,
|
|
"{ \r\n\t"+`"md.1":{ `+"\r\n\t"+`
|
|
|
|
"subkey1": "value\n with\n newlines",
|
|
|
|
"subkey2": true
|
|
}
|
|
}`), mustParseMd(t, `{"md.1":{"subkey1":"value\n with\n newlines", "subkey2":true}}`), true},
|
|
}
|
|
|
|
for _, tc := range tcs {
|
|
if tc.a.Equals(tc.b) != tc.equals {
|
|
t.Errorf("Annotations equality mismatch - expecting (%v == %v) = %v", tc.b, tc.a, tc.equals)
|
|
}
|
|
if tc.b.Equals(tc.a) != tc.equals {
|
|
t.Errorf("Annotations reflexive equality mismatch - expecting (%v == %v) = %v", tc.b, tc.a, tc.equals)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
var annCases = []struct {
|
|
val *testObj
|
|
valString string
|
|
}{
|
|
{val: &testObj{Md: EmptyAnnotations()}, valString: "{}"},
|
|
{val: &testObj{Md: EmptyAnnotations().withRawKey("stringval", `"bar"`)}, valString: `{"annotations":{"stringval":"bar"}}`},
|
|
{val: &testObj{Md: EmptyAnnotations().withRawKey("intval", `1001`)}, valString: `{"annotations":{"intval":1001}}`},
|
|
{val: &testObj{Md: EmptyAnnotations().withRawKey("floatval", "3.141")}, valString: `{"annotations":{"floatval":3.141}}`},
|
|
{val: &testObj{Md: EmptyAnnotations().withRawKey("objval", `{"foo":"fooval","bar":"barval"}`)}, valString: `{"annotations":{"objval":{"foo":"fooval","bar":"barval"}}}`},
|
|
{val: &testObj{Md: EmptyAnnotations().withRawKey("objval", `{"foo":"fooval","bar":{"barbar":"barbarval"}}`)}, valString: `{"annotations":{"objval":{"foo":"fooval","bar":{"barbar":"barbarval"}}}}`},
|
|
{val: &testObj{Md: EmptyAnnotations().withRawKey("objval", `{"foo":"JSON newline \\n string"}`)}, valString: `{"annotations":{"objval":{"foo":"JSON newline \\n string"}}}`},
|
|
}
|
|
|
|
func TestAnnotationsJSONMarshalling(t *testing.T) {
|
|
|
|
for _, tc := range annCases {
|
|
v, err := json.Marshal(tc.val)
|
|
if err != nil {
|
|
t.Fatalf("Failed to marshal json into %s: %v", tc.valString, err)
|
|
}
|
|
if string(v) != tc.valString {
|
|
t.Errorf("Invalid annotations value, expected %s, got %s", tc.valString, string(v))
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func TestAnnotationsJSONUnMarshalling(t *testing.T) {
|
|
|
|
for _, tc := range annCases {
|
|
tv := testObj{}
|
|
err := json.Unmarshal([]byte(tc.valString), &tv)
|
|
if err != nil {
|
|
t.Fatalf("Failed to unmarshal json into %s: %v", tc.valString, err)
|
|
}
|
|
if !reflect.DeepEqual(&tv, tc.val) {
|
|
t.Errorf("Invalid annotations value, expected %v, got %v", tc.val, tv)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func TestAnnotationsWithHonorsKeyLimits(t *testing.T) {
|
|
var validKeys = []string{
|
|
"ok",
|
|
strings.Repeat("a", maxAnnotationKeyBytes),
|
|
"fnproject/internal/foo",
|
|
"foo.bar.com.baz",
|
|
"foo$bar!_+-()[]:@/<>$",
|
|
}
|
|
for _, k := range validKeys {
|
|
m, err := EmptyAnnotations().With(k, "value")
|
|
|
|
if err != nil {
|
|
t.Errorf("Should have accepted valid key %s,%v", k, err)
|
|
}
|
|
|
|
err = m.Validate()
|
|
if err != nil {
|
|
t.Errorf("Should have validate valid key %s,%v", k, err)
|
|
}
|
|
|
|
}
|
|
|
|
var invalidKeys = []struct {
|
|
key string
|
|
err APIError
|
|
}{
|
|
{"", ErrInvalidAnnotationKey},
|
|
{" ", ErrInvalidAnnotationKey},
|
|
{"\u00e9", ErrInvalidAnnotationKey},
|
|
{"foo bar", ErrInvalidAnnotationKey},
|
|
{strings.Repeat("a", maxAnnotationKeyBytes+1), ErrInvalidAnnotationKeyLength},
|
|
}
|
|
for _, kc := range invalidKeys {
|
|
_, err := EmptyAnnotations().With(kc.key, "value")
|
|
if err == nil {
|
|
t.Errorf("Should have rejected invalid key %s", kc.key)
|
|
}
|
|
|
|
m := EmptyAnnotations().withRawKey(kc.key, "\"data\"")
|
|
err = m.Validate()
|
|
if err != kc.err {
|
|
t.Errorf("Should have returned validation error %v, for key %s got %v", kc.err, kc.key, err)
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func TestAnnotationsHonorsValueLimits(t *testing.T) {
|
|
validValues := []interface{}{
|
|
"ok",
|
|
&myJson{Foo: "foo"},
|
|
strings.Repeat("a", maxAnnotationValueBytes-2),
|
|
[]string{strings.Repeat("a", maxAnnotationValueBytes-4)},
|
|
|
|
1,
|
|
[]string{"a", "b", "c"},
|
|
true,
|
|
}
|
|
|
|
for _, v := range validValues {
|
|
|
|
_, err := EmptyAnnotations().With("key", v)
|
|
if err != nil {
|
|
t.Errorf("Should have accepted valid value %s,%v", v, err)
|
|
}
|
|
|
|
rawJson, err := json.Marshal(v)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
md := EmptyAnnotations().withRawKey("key", string(rawJson))
|
|
|
|
err = md.Validate()
|
|
if err != nil {
|
|
t.Errorf("Should have validated valid value successfully %s, got error %v", string(rawJson), err)
|
|
}
|
|
}
|
|
|
|
invalidValues := []struct {
|
|
val interface{}
|
|
err APIError
|
|
}{
|
|
{"", ErrInvalidAnnotationValue},
|
|
{nil, ErrInvalidAnnotationValue},
|
|
{strings.Repeat("a", maxAnnotationValueBytes-1), ErrInvalidAnnotationValueLength},
|
|
{[]string{strings.Repeat("a", maxAnnotationValueBytes-3)}, ErrInvalidAnnotationValueLength},
|
|
}
|
|
|
|
for _, v := range invalidValues {
|
|
_, err := EmptyAnnotations().With("key", v.val)
|
|
if err == nil {
|
|
t.Errorf("Should have rejected invalid value \"%v\"", v)
|
|
}
|
|
|
|
rawJson, err := json.Marshal(v.val)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
md := EmptyAnnotations().withRawKey("key", string(rawJson))
|
|
|
|
err = md.Validate()
|
|
if err != v.err {
|
|
t.Errorf("Expected validation error %v for '%s', got %v", v.err, string(rawJson), err)
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
func TestMergeAnnotations(t *testing.T) {
|
|
|
|
mdWithNKeys := func(n int) Annotations {
|
|
md := EmptyAnnotations()
|
|
for i := 0; i < n; i++ {
|
|
md = md.withRawKey(fmt.Sprintf("key-%d", i), "val")
|
|
}
|
|
return md
|
|
}
|
|
validCases := []struct {
|
|
first Annotations
|
|
second Annotations
|
|
result Annotations
|
|
}{
|
|
{first: EmptyAnnotations(), second: EmptyAnnotations(), result: EmptyAnnotations()},
|
|
{first: EmptyAnnotations().withRawKey("key1", "\"val\""), second: EmptyAnnotations(), result: EmptyAnnotations().withRawKey("key1", "\"val\"")},
|
|
{first: EmptyAnnotations(), second: EmptyAnnotations().withRawKey("key1", "\"val\""), result: EmptyAnnotations().withRawKey("key1", "\"val\"")},
|
|
{first: EmptyAnnotations().withRawKey("key1", "\"val\""), second: EmptyAnnotations().withRawKey("key1", "\"val\""), result: EmptyAnnotations().withRawKey("key1", "\"val\"")},
|
|
{first: EmptyAnnotations().withRawKey("key1", "\"val1\""), second: EmptyAnnotations().withRawKey("key2", "\"val2\""), result: EmptyAnnotations().withRawKey("key1", "\"val1\"").withRawKey("key2", "\"val2\"")},
|
|
{first: EmptyAnnotations().withRawKey("key1", "\"val1\""), second: EmptyAnnotations().withRawKey("key1", "\"\""), result: EmptyAnnotations()},
|
|
{first: EmptyAnnotations().withRawKey("key1", "\"val1\""), second: EmptyAnnotations().withRawKey("key2", "\"\""), result: EmptyAnnotations().withRawKey("key1", "\"val1\"")},
|
|
{first: mdWithNKeys(maxAnnotationsKeys - 1), second: EmptyAnnotations().withRawKey("newkey", "\"val\""), result: mdWithNKeys(maxAnnotationsKeys-1).withRawKey("newkey", "\"val\"")},
|
|
}
|
|
|
|
for _, v := range validCases {
|
|
newMd := v.first.MergeChange(v.second)
|
|
|
|
if !reflect.DeepEqual(newMd, v.result) {
|
|
t.Errorf("Change %v + %v : expected %v got %v", v.first, v.second, v.result, newMd)
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func TestGetAnnotations(t *testing.T) {
|
|
annotations := EmptyAnnotations()
|
|
annotations, err := annotations.With("string-annotation", "string-value")
|
|
if err != nil {
|
|
t.Fatal("Cannot add string annotation")
|
|
}
|
|
annotations, err = annotations.With("array-annotation", []string{"string-1", "string-2"})
|
|
if err != nil {
|
|
t.Fatal("Cannot add array annotation")
|
|
}
|
|
strAnnotation, ok := annotations.Get("string-annotation")
|
|
if !ok {
|
|
t.Error("Cannot get string annotation")
|
|
}
|
|
expected := "\"string-value\""
|
|
if string(strAnnotation) != expected {
|
|
t.Errorf("Got unexpected value for string annotation. Got: %s Expected %s", strAnnotation, expected)
|
|
}
|
|
arrAnnotation, ok := annotations.Get("array-annotation")
|
|
if !ok {
|
|
t.Error("Cannot get array annotation")
|
|
}
|
|
expected = "[\"string-1\",\"string-2\"]"
|
|
if string(arrAnnotation) != expected {
|
|
t.Errorf("Got unexpected value for array annotation. Got: %s Expected %s", strAnnotation, expected)
|
|
}
|
|
|
|
stringAnnotation, err := annotations.GetString("string-annotation")
|
|
if err != nil {
|
|
t.Fatalf("Error decoding string annotation: %v", err)
|
|
}
|
|
expected = "string-value"
|
|
if stringAnnotation != expected {
|
|
t.Errorf("Got unexpected decoded value for string annotation. Got: %s Expected %s", strAnnotation, expected)
|
|
}
|
|
|
|
_, err = annotations.GetString("array-annotation")
|
|
if err == nil {
|
|
t.Error("Expected error trying to retrieve a string value for array annotation")
|
|
}
|
|
}
|