1 package configx 2 3 import ( 4 "context" 5 "io/ioutil" 6 "path" 7 "testing" 8 9 "github.com/inhies/go-bytesize" 10 11 "github.com/knadh/koanf/parsers/json" 12 13 "github.com/ory/x/urlx" 14 15 "github.com/spf13/pflag" 16 17 "github.com/stretchr/testify/assert" 18 "github.com/stretchr/testify/require" 19 ) 20 21 func TestProviderMethods(t *testing.T) { 22 // Fake some flags 23 f := pflag.NewFlagSet("config", pflag.ContinueOnError) 24 f.String("foo-bar-baz", "", "") 25 f.StringP("b", "b", "", "") 26 args := []string{"/var/folders/mt/m1dwr59n73zgsq7bk0q2lrmc0000gn/T/go-build533083141/b001/exe/asdf", "aaaa", "-b", "bbbb", "dddd", "eeee", "--foo-bar-baz", "fff"} 27 require.NoError(t, f.Parse(args[1:])) 28 RegisterFlags(f) 29 30 ctx, cancel := context.WithCancel(context.Background()) 31 defer cancel() 32 33 p, err := New([]byte(`{}`), WithFlags(f), WithContext(ctx)) 34 require.NoError(t, err) 35 36 t.Run("check flags", func(t *testing.T) { 37 assert.Equal(t, "fff", p.String("foo-bar-baz")) 38 assert.Equal(t, "bbbb", p.String("b")) 39 }) 40 41 t.Run("check fallbacks", func(t *testing.T) { 42 t.Run("type=string", func(t *testing.T) { 43 require.NoError(t, p.Set("some.string", "bar")) 44 assert.Equal(t, "bar", p.StringF("some.string", "baz")) 45 assert.Equal(t, "baz", p.StringF("not.some.string", "baz")) 46 }) 47 48 t.Run("type=float", func(t *testing.T) { 49 require.NoError(t, p.Set("some.float", 123.123)) 50 assert.Equal(t, 123.123, p.Float64F("some.float", 321.321)) 51 assert.Equal(t, 321.321, p.Float64F("not.some.float", 321.321)) 52 }) 53 54 t.Run("type=int", func(t *testing.T) { 55 require.NoError(t, p.Set("some.int", 123)) 56 assert.Equal(t, 123, p.IntF("some.int", 123)) 57 assert.Equal(t, 321, p.IntF("not.some.int", 321)) 58 }) 59 60 t.Run("type=bytesize", func(t *testing.T) { 61 const key = "some.bytesize" 62 63 for _, v := range []interface{}{ 64 bytesize.MB, 65 float64(1024 * 1024), 66 "1MB", 67 } { 68 require.NoError(t, p.Set(key, v)) 69 assert.Equal(t, bytesize.MB, p.ByteSizeF(key, 0)) 70 } 71 }) 72 73 github := urlx.ParseOrPanic("https://github.com/ory") 74 ory := urlx.ParseOrPanic("https://www.ory.sh/") 75 76 t.Run("type=url", func(t *testing.T) { 77 require.NoError(t, p.Set("some.url", "https://github.com/ory")) 78 assert.Equal(t, github, p.URIF("some.url", ory)) 79 assert.Equal(t, ory, p.URIF("not.some.url", ory)) 80 }) 81 82 t.Run("type=request_uri", func(t *testing.T) { 83 require.NoError(t, p.Set("some.request_uri", "https://github.com/ory")) 84 assert.Equal(t, github, p.RequestURIF("some.request_uri", ory)) 85 assert.Equal(t, ory, p.RequestURIF("not.some.request_uri", ory)) 86 87 require.NoError(t, p.Set("invalid.request_uri", "foo")) 88 assert.Equal(t, ory, p.RequestURIF("invalid.request_uri", ory)) 89 }) 90 }) 91 92 t.Run("use complex set operations", func(t *testing.T) { 93 assert.NoError(t, p.Set("nested", nil)) 94 assert.NoError(t, p.Set("nested.value", "https://www.ory.sh/kratos")) 95 assert.Equal(t, "https://www.ory.sh/kratos", p.Get("nested.value")) 96 }) 97 } 98 99 func TestAdvancedConfigs(t *testing.T) { 100 for _, tc := range []struct { 101 stub string 102 configs []string 103 envs [][2]string 104 isValid bool 105 expectedF func(*testing.T, *Provider) 106 }{ 107 { 108 stub: "kratos", 109 configs: []string{"stub/kratos/kratos.yaml"}, 110 isValid: true, envs: [][2]string{ 111 {"DSN", "sqlite:///var/lib/sqlite/db.sqlite?_fk=true"}, 112 }}, 113 { 114 stub: "multi", 115 configs: []string{"stub/multi/a.yaml", "stub/multi/b.yaml"}, 116 isValid: true, envs: [][2]string{ 117 {"DSN", "sqlite:///var/lib/sqlite/db.sqlite?_fk=true"}, 118 }}, 119 { 120 stub: "hydra", 121 configs: []string{"stub/hydra/hydra.yaml"}, 122 isValid: true, 123 envs: [][2]string{ 124 {"DSN", "sqlite:///var/lib/sqlite/db.sqlite?_fk=true"}, 125 {"TRACING_PROVIDER", "jaeger"}, 126 {"TRACING_PROVIDERS_JAEGER_SAMPLING_SERVER_URL", "http://jaeger:5778/sampling"}, 127 {"TRACING_PROVIDERS_JAEGER_LOCAL_AGENT_ADDRESS", "jaeger:6832"}, 128 {"TRACING_PROVIDERS_JAEGER_SAMPLING_TYPE", "const"}, 129 {"TRACING_PROVIDERS_JAEGER_SAMPLING_VALUE", "1"}, 130 }, 131 expectedF: func(t *testing.T, p *Provider) { 132 assert.Equal(t, "sqlite:///var/lib/sqlite/db.sqlite?_fk=true", p.Get("dsn")) 133 assert.Equal(t, "jaeger", p.Get("tracing.provider")) 134 assert.Equal(t, "jaeger:6832", p.Get("tracing.providers.jaeger.local_agent_address")) 135 }}, 136 { 137 stub: "hydra", 138 configs: []string{"stub/hydra/hydra.yaml"}, 139 isValid: false, envs: [][2]string{ 140 {"DSN", "sqlite:///var/lib/sqlite/db.sqlite?_fk=true"}, 141 {"TRACING_PROVIDER", "not-jaeger"}, 142 }}, 143 } { 144 t.Run("service="+tc.stub, func(t *testing.T) { 145 setEnvs(t, tc.envs) 146 147 expected, err := ioutil.ReadFile(path.Join("stub", tc.stub, "expected.json")) 148 require.NoError(t, err) 149 150 schemaPath := path.Join("stub", tc.stub, "config.schema.json") 151 ctx, cancel := context.WithCancel(context.Background()) 152 defer cancel() 153 k, err := newKoanf(schemaPath, tc.configs, WithContext(ctx)) 154 if !tc.isValid { 155 require.Error(t, err) 156 return 157 } 158 require.NoError(t, err) 159 160 out, err := k.Koanf.Marshal(json.Parser()) 161 require.NoError(t, err) 162 assert.JSONEq(t, string(expected), string(out), "%s", out) 163 164 if tc.expectedF != nil { 165 tc.expectedF(t, k) 166 } 167 }) 168 } 169 } 170