diff --git a/fs/config/configmap/configmap.go b/fs/config/configmap/configmap.go index c26b7869b..a37a2e654 100644 --- a/fs/config/configmap/configmap.go +++ b/fs/config/configmap/configmap.go @@ -2,8 +2,13 @@ package configmap import ( + "encoding/base64" + "encoding/json" "sort" "strings" + "unicode" + + "github.com/pkg/errors" ) // Priority of getters @@ -159,3 +164,38 @@ func (c Simple) String() string { } return out.String() } + +// Encode from c into a string suitable for putting on the command line +func (c Simple) Encode() (string, error) { + if len(c) == 0 { + return "", nil + } + buf, err := json.Marshal(c) + if err != nil { + return "", errors.Wrap(err, "encode simple map") + } + return base64.RawStdEncoding.EncodeToString(buf), nil +} + +// Decode an Encode~d string in into c +func (c Simple) Decode(in string) error { + // Remove all whitespace from the input string + in = strings.Map(func(r rune) rune { + if unicode.IsSpace(r) { + return -1 + } + return r + }, in) + if len(in) == 0 { + return nil + } + decodedM, err := base64.RawStdEncoding.DecodeString(in) + if err != nil { + return errors.Wrap(err, "decode simple map") + } + err = json.Unmarshal(decodedM, &c) + if err != nil { + return errors.Wrap(err, "parse simple map") + } + return nil +} diff --git a/fs/config/configmap/configmap_test.go b/fs/config/configmap/configmap_test.go index 23c84478b..85d4686f1 100644 --- a/fs/config/configmap/configmap_test.go +++ b/fs/config/configmap/configmap_test.go @@ -1,9 +1,11 @@ package configmap import ( + "encoding/base64" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var ( @@ -267,3 +269,91 @@ func TestSimpleString(t *testing.T) { "apple": "", }.String()) } + +func TestSimpleEncode(t *testing.T) { + for _, test := range []struct { + in Simple + want string + }{ + { + in: Simple{}, + want: "", + }, + { + in: Simple{ + "one": "potato", + }, + want: "eyJvbmUiOiJwb3RhdG8ifQ", + }, + { + in: Simple{ + "one": "potato", + "two": "", + }, + want: "eyJvbmUiOiJwb3RhdG8iLCJ0d28iOiIifQ", + }, + } { + got, err := test.in.Encode() + require.NoError(t, err) + assert.Equal(t, test.want, got) + gotM := Simple{} + err = gotM.Decode(got) + require.NoError(t, err) + assert.Equal(t, test.in, gotM) + } +} + +func TestSimpleDecode(t *testing.T) { + for _, test := range []struct { + in string + want Simple + wantErr string + }{ + { + in: "", + want: Simple{}, + }, + { + in: "eyJvbmUiOiJwb3RhdG8ifQ", + want: Simple{ + "one": "potato", + }, + }, + { + in: " e yJvbm UiOiJwb\r\n 3Rhd\tG8ifQ\n\n ", + want: Simple{ + "one": "potato", + }, + }, + { + in: "eyJvbmUiOiJwb3RhdG8iLCJ0d28iOiIifQ", + want: Simple{ + "one": "potato", + "two": "", + }, + }, + { + in: "!!!!!", + want: Simple{}, + wantErr: "decode simple map", + }, + { + in: base64.RawStdEncoding.EncodeToString([]byte(`null`)), + want: Simple{}, + }, + { + in: base64.RawStdEncoding.EncodeToString([]byte(`rubbish`)), + want: Simple{}, + wantErr: "parse simple map", + }, + } { + got := Simple{} + err := got.Decode(test.in) + assert.Equal(t, test.want, got, test.in) + if test.wantErr == "" { + require.NoError(t, err, test.in) + } else { + assert.Contains(t, err.Error(), test.wantErr, test.in) + } + } +}