mirror of
https://github.com/kemko/nomad.git
synced 2026-01-07 10:55:42 +03:00
As part of deprecating legacy drivers, we're moving the env package to a new drivers/shared tree, as it is used by the modern docker and rkt driver packages, and is useful for 3rd party plugins.
410 lines
7.5 KiB
Go
410 lines
7.5 KiB
Go
package env
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
// TestAddNestedKey_Ok asserts test cases that succeed when passed to
|
|
// addNestedKey.
|
|
func TestAddNestedKey_Ok(t *testing.T) {
|
|
cases := []struct {
|
|
// M will be initialized if unset
|
|
M map[string]interface{}
|
|
K string
|
|
// Value is always "x"
|
|
Result map[string]interface{}
|
|
}{
|
|
{
|
|
K: "foo",
|
|
Result: map[string]interface{}{
|
|
"foo": "x",
|
|
},
|
|
},
|
|
{
|
|
K: "foo.bar",
|
|
Result: map[string]interface{}{
|
|
"foo": map[string]interface{}{
|
|
"bar": "x",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
K: "foo.bar.quux",
|
|
Result: map[string]interface{}{
|
|
"foo": map[string]interface{}{
|
|
"bar": map[string]interface{}{
|
|
"quux": "x",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
K: "a.b.c",
|
|
Result: map[string]interface{}{
|
|
"a": map[string]interface{}{
|
|
"b": map[string]interface{}{
|
|
"c": "x",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
// Nested object b should get overwritten with "x"
|
|
M: map[string]interface{}{
|
|
"a": map[string]interface{}{
|
|
"b": map[string]interface{}{
|
|
"c": "c",
|
|
},
|
|
},
|
|
},
|
|
K: "a.b",
|
|
Result: map[string]interface{}{
|
|
"a": map[string]interface{}{
|
|
"b": "x",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
M: map[string]interface{}{
|
|
"a": map[string]interface{}{
|
|
"x": "x",
|
|
},
|
|
"z": "z",
|
|
},
|
|
K: "a.b.c",
|
|
Result: map[string]interface{}{
|
|
"a": map[string]interface{}{
|
|
"b": map[string]interface{}{
|
|
"c": "x",
|
|
},
|
|
"x": "x",
|
|
},
|
|
"z": "z",
|
|
},
|
|
},
|
|
{
|
|
M: map[string]interface{}{
|
|
"foo": map[string]interface{}{
|
|
"bar": map[string]interface{}{
|
|
"a": "z",
|
|
"quux": "z",
|
|
},
|
|
},
|
|
},
|
|
K: "foo.bar.quux",
|
|
Result: map[string]interface{}{
|
|
"foo": map[string]interface{}{
|
|
"bar": map[string]interface{}{
|
|
"a": "z",
|
|
"quux": "x",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
M: map[string]interface{}{
|
|
"foo": "1",
|
|
"bar": "2",
|
|
"quux": "3",
|
|
},
|
|
K: "a.bbbbbb.c",
|
|
Result: map[string]interface{}{
|
|
"foo": "1",
|
|
"bar": "2",
|
|
"quux": "3",
|
|
"a": map[string]interface{}{
|
|
"bbbbbb": map[string]interface{}{
|
|
"c": "x",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for i := range cases {
|
|
tc := cases[i]
|
|
name := tc.K
|
|
if len(tc.M) > 0 {
|
|
name = fmt.Sprintf("%s-%d", name, len(tc.M))
|
|
}
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
if tc.M == nil {
|
|
tc.M = map[string]interface{}{}
|
|
}
|
|
require.NoError(t, addNestedKey(tc.M, tc.K, "x"))
|
|
require.Equal(t, tc.Result, tc.M)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestAddNestedKey_Bad asserts test cases return an error when passed to
|
|
// addNestedKey.
|
|
func TestAddNestedKey_Bad(t *testing.T) {
|
|
cases := []struct {
|
|
// M will be initialized if unset
|
|
M func() map[string]interface{}
|
|
K string
|
|
// Value is always "x"
|
|
// Result is compared by Error() string equality
|
|
Result error
|
|
}{
|
|
{
|
|
K: ".",
|
|
Result: ErrInvalidObjectPath,
|
|
},
|
|
{
|
|
K: ".foo",
|
|
Result: ErrInvalidObjectPath,
|
|
},
|
|
{
|
|
K: "foo.",
|
|
Result: ErrInvalidObjectPath,
|
|
},
|
|
{
|
|
K: ".a.",
|
|
Result: ErrInvalidObjectPath,
|
|
},
|
|
{
|
|
K: "foo..bar",
|
|
Result: ErrInvalidObjectPath,
|
|
},
|
|
{
|
|
K: "foo...bar",
|
|
Result: ErrInvalidObjectPath,
|
|
},
|
|
{
|
|
K: "foo.bar..quux",
|
|
Result: ErrInvalidObjectPath,
|
|
},
|
|
{
|
|
K: "foo..bar.quux",
|
|
Result: ErrInvalidObjectPath,
|
|
},
|
|
{
|
|
K: "foo.bar.quux.",
|
|
Result: ErrInvalidObjectPath,
|
|
},
|
|
{
|
|
M: func() map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"a": "a",
|
|
"foo": map[string]interface{}{
|
|
"b": "b",
|
|
"bar": map[string]interface{}{
|
|
"c": "c",
|
|
},
|
|
},
|
|
}
|
|
},
|
|
K: "foo.bar.quux.",
|
|
Result: ErrInvalidObjectPath,
|
|
},
|
|
{
|
|
M: func() map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"a": "a",
|
|
"foo": map[string]interface{}{
|
|
"b": "b",
|
|
"bar": map[string]interface{}{
|
|
"c": "c",
|
|
},
|
|
},
|
|
}
|
|
},
|
|
K: "foo.bar..quux",
|
|
Result: ErrInvalidObjectPath,
|
|
},
|
|
{
|
|
M: func() map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"a": "a",
|
|
"foo": map[string]interface{}{
|
|
"b": "b",
|
|
"bar": map[string]interface{}{
|
|
"c": "c",
|
|
},
|
|
},
|
|
}
|
|
},
|
|
K: "foo.bar..quux",
|
|
Result: ErrInvalidObjectPath,
|
|
},
|
|
{
|
|
M: func() map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"a": "a",
|
|
}
|
|
},
|
|
K: "a.b",
|
|
Result: NewErrKeyExists("a.b", "a"),
|
|
},
|
|
{
|
|
M: func() map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"a": "a",
|
|
"foo": map[string]interface{}{
|
|
"b": "b",
|
|
"bar": "quux",
|
|
},
|
|
"c": map[string]interface{}{},
|
|
}
|
|
},
|
|
K: "foo.bar.quux",
|
|
Result: NewErrKeyExists("foo.bar.quux", "bar"),
|
|
},
|
|
{
|
|
M: func() map[string]interface{} {
|
|
return map[string]interface{}{
|
|
"a": map[string]interface{}{
|
|
"b": "b",
|
|
},
|
|
}
|
|
},
|
|
K: "a.b.c.",
|
|
Result: NewErrKeyExists("a.b.c.", "b"),
|
|
},
|
|
}
|
|
|
|
for i := range cases {
|
|
tc := cases[i]
|
|
name := tc.K
|
|
if tc.M != nil {
|
|
name += "-cleanup"
|
|
}
|
|
t.Run(name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// Copy original M value to ensure it doesn't get altered
|
|
if tc.M == nil {
|
|
tc.M = func() map[string]interface{} {
|
|
return map[string]interface{}{}
|
|
}
|
|
}
|
|
|
|
// Call func and assert error
|
|
m := tc.M()
|
|
err := addNestedKey(m, tc.K, "x")
|
|
require.EqualError(t, err, tc.Result.Error())
|
|
|
|
// Ensure M wasn't altered
|
|
require.Equal(t, tc.M(), m)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCtyify_Ok(t *testing.T) {
|
|
cases := []struct {
|
|
Name string
|
|
In map[string]interface{}
|
|
Out map[string]cty.Value
|
|
}{
|
|
{
|
|
Name: "OneVal",
|
|
In: map[string]interface{}{
|
|
"a": "b",
|
|
},
|
|
Out: map[string]cty.Value{
|
|
"a": cty.StringVal("b"),
|
|
},
|
|
},
|
|
{
|
|
Name: "MultiVal",
|
|
In: map[string]interface{}{
|
|
"a": "b",
|
|
"foo": "bar",
|
|
},
|
|
Out: map[string]cty.Value{
|
|
"a": cty.StringVal("b"),
|
|
"foo": cty.StringVal("bar"),
|
|
},
|
|
},
|
|
{
|
|
Name: "NestedVals",
|
|
In: map[string]interface{}{
|
|
"a": "b",
|
|
"foo": map[string]interface{}{
|
|
"c": "d",
|
|
"bar": map[string]interface{}{
|
|
"quux": "z",
|
|
},
|
|
},
|
|
"123": map[string]interface{}{
|
|
"bar": map[string]interface{}{
|
|
"456": "789",
|
|
},
|
|
},
|
|
},
|
|
Out: map[string]cty.Value{
|
|
"a": cty.StringVal("b"),
|
|
"foo": cty.ObjectVal(map[string]cty.Value{
|
|
"c": cty.StringVal("d"),
|
|
"bar": cty.ObjectVal(map[string]cty.Value{
|
|
"quux": cty.StringVal("z"),
|
|
}),
|
|
}),
|
|
"123": cty.ObjectVal(map[string]cty.Value{
|
|
"bar": cty.ObjectVal(map[string]cty.Value{
|
|
"456": cty.StringVal("789"),
|
|
}),
|
|
}),
|
|
},
|
|
},
|
|
}
|
|
|
|
for i := range cases {
|
|
tc := cases[i]
|
|
t.Run(tc.Name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// ctiyif and check for errors
|
|
result, err := ctyify(tc.In)
|
|
require.NoError(t, err)
|
|
|
|
// convert results to ObjectVals and compare with RawEquals
|
|
resultObj := cty.ObjectVal(result)
|
|
OutObj := cty.ObjectVal(tc.Out)
|
|
require.True(t, OutObj.RawEquals(resultObj))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCtyify_Bad(t *testing.T) {
|
|
cases := []struct {
|
|
Name string
|
|
In map[string]interface{}
|
|
Out map[string]cty.Value
|
|
}{
|
|
{
|
|
Name: "NonStringVal",
|
|
In: map[string]interface{}{
|
|
"a": 1,
|
|
},
|
|
},
|
|
{
|
|
Name: "NestedNonString",
|
|
In: map[string]interface{}{
|
|
"foo": map[string]interface{}{
|
|
"c": 1,
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for i := range cases {
|
|
tc := cases[i]
|
|
t.Run(tc.Name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// ctiyif and check for errors
|
|
result, err := ctyify(tc.In)
|
|
require.Error(t, err)
|
|
require.Nil(t, result)
|
|
})
|
|
}
|
|
}
|