From 814d0d0a219e530e86623f08bece1defe154212c Mon Sep 17 00:00:00 2001 From: Peter Csajtai Date: Mon, 15 May 2023 15:04:06 +0200 Subject: [PATCH] Rename "Environments" => "SDKs" --- config/config.go | 22 ++++++------- config/config_test.go | 58 ++++++++++++++++---------------- config/env.go | 14 ++++---- config/env_test.go | 62 +++++++++++++++++------------------ config/validate.go | 4 +-- config/validate_test.go | 44 ++++++++++++------------- docker-compose.yml | 22 ++++++------- internal/resources/config.yml | 4 +-- internal/utils/utils.go | 4 +-- main.go | 2 +- status/mware_test.go | 6 ++-- status/status.go | 6 ++-- status/status_test.go | 28 ++++++++-------- web/api/api.go | 14 +++++--- web/api/api_test.go | 30 ++++++++--------- web/cdnproxy/cdnproxy.go | 10 +++--- web/cdnproxy/cdnproxy_test.go | 20 +++++------ web/router.go | 17 +++++----- web/router_status_test.go | 2 +- web/sse/sse.go | 10 +++--- web/sse/sse_test.go | 4 +-- web/webhook/webhook.go | 10 +++--- web/webhook/webhook_test.go | 12 +++---- 23 files changed, 205 insertions(+), 200 deletions(-) diff --git a/config/config.go b/config/config.go index f258243..3d6220a 100644 --- a/config/config.go +++ b/config/config.go @@ -25,15 +25,15 @@ var allowedTlsVersions = map[float64]uint16{ } type Config struct { - Log LogConfig - Environments map[string]*SDKConfig - Grpc GrpcConfig - Tls TlsConfig - Metrics MetricsConfig - Http HttpConfig - HttpProxy HttpProxyConfig `yaml:"http_proxy"` - EvalStats EvalStatsConfig `yaml:"eval_stats"` - Cache CacheConfig + Log LogConfig + SDKs map[string]*SDKConfig + Grpc GrpcConfig + Tls TlsConfig + Metrics MetricsConfig + Http HttpConfig + HttpProxy HttpProxyConfig `yaml:"http_proxy"` + EvalStats EvalStatsConfig `yaml:"eval_stats"` + Cache CacheConfig } type SDKConfig struct { @@ -228,7 +228,7 @@ func (c *Config) setDefaults() { } func (c *Config) fixupDefaults() { - for _, env := range c.Environments { + for _, env := range c.SDKs { if env == nil { continue } @@ -248,7 +248,7 @@ func (c *Config) fixupDefaults() { } func (c *Config) fixupLogLevels(defLevel string) { - for _, env := range c.Environments { + for _, env := range c.SDKs { if env == nil { continue } diff --git a/config/config_test.go b/config/config_test.go index 0154ef2..6eb4dd8 100644 --- a/config/config_test.go +++ b/config/config_test.go @@ -45,8 +45,8 @@ func TestConfig_Defaults(t *testing.T) { func TestConfig_LogLevelFixup(t *testing.T) { t.Run("valid base level", func(t *testing.T) { utils.UseTempFile(` -environments: - test_env: +sdks: + test_sdk: key: key log: level: "info" @@ -55,8 +55,8 @@ log: require.NoError(t, err) assert.Equal(t, log.Info, conf.Log.GetLevel()) - assert.Equal(t, log.Info, conf.Environments["test_env"].Log.GetLevel()) - assert.Equal(t, log.Info, conf.Environments["test_env"].Offline.Log.GetLevel()) + assert.Equal(t, log.Info, conf.SDKs["test_sdk"].Log.GetLevel()) + assert.Equal(t, log.Info, conf.SDKs["test_sdk"].Offline.Log.GetLevel()) assert.Equal(t, log.Info, conf.Http.Log.GetLevel()) assert.Equal(t, log.Info, conf.Http.Sse.Log.GetLevel()) assert.Equal(t, log.Info, conf.Grpc.Log.GetLevel()) @@ -65,8 +65,8 @@ log: t.Run("invalid base level", func(t *testing.T) { utils.UseTempFile(` -environments: - test_env: +sdks: + test_sdk: key: key log: level: "invalid" @@ -75,8 +75,8 @@ log: require.NoError(t, err) assert.Equal(t, log.Warn, conf.Log.GetLevel()) - assert.Equal(t, log.Warn, conf.Environments["test_env"].Log.GetLevel()) - assert.Equal(t, log.Warn, conf.Environments["test_env"].Offline.Log.GetLevel()) + assert.Equal(t, log.Warn, conf.SDKs["test_sdk"].Log.GetLevel()) + assert.Equal(t, log.Warn, conf.SDKs["test_sdk"].Offline.Log.GetLevel()) assert.Equal(t, log.Warn, conf.Http.Log.GetLevel()) assert.Equal(t, log.Warn, conf.Http.Sse.Log.GetLevel()) assert.Equal(t, log.Warn, conf.Grpc.Log.GetLevel()) @@ -87,8 +87,8 @@ log: utils.UseTempFile(` log: level: "error" -environments: - test_env: +sdks: + test_sdk: log: level: "debug" offline: @@ -108,8 +108,8 @@ grpc: require.NoError(t, err) assert.Equal(t, log.Error, conf.Log.GetLevel()) - assert.Equal(t, log.Debug, conf.Environments["test_env"].Log.GetLevel()) - assert.Equal(t, log.Debug, conf.Environments["test_env"].Offline.Log.GetLevel()) + assert.Equal(t, log.Debug, conf.SDKs["test_sdk"].Log.GetLevel()) + assert.Equal(t, log.Debug, conf.SDKs["test_sdk"].Offline.Log.GetLevel()) assert.Equal(t, log.Debug, conf.Http.Log.GetLevel()) assert.Equal(t, log.Debug, conf.Http.Sse.Log.GetLevel()) assert.Equal(t, log.Debug, conf.Grpc.Log.GetLevel()) @@ -119,8 +119,8 @@ grpc: func TestSDKConfig_YAML(t *testing.T) { utils.UseTempFile(` -environments: - test_env: +sdks: + test_sdk: base_url: "base" key: "sdkKey" poll_interval: 300 @@ -143,21 +143,21 @@ environments: conf, err := LoadConfigFromFileAndEnvironment(file) require.NoError(t, err) - assert.Equal(t, "base", conf.Environments["test_env"].BaseUrl) - assert.Equal(t, "sdkKey", conf.Environments["test_env"].Key) - assert.Equal(t, 300, conf.Environments["test_env"].PollInterval) - assert.Equal(t, "eu", conf.Environments["test_env"].DataGovernance) - assert.Equal(t, log.Error, conf.Environments["test_env"].Log.GetLevel()) - assert.Equal(t, "key", conf.Environments["test_env"].WebhookSigningKey) - assert.Equal(t, 600, conf.Environments["test_env"].WebhookSignatureValidFor) - - assert.True(t, conf.Environments["test_env"].Offline.Enabled) - assert.Equal(t, log.Debug, conf.Environments["test_env"].Offline.Log.GetLevel()) - assert.Equal(t, "./local.json", conf.Environments["test_env"].Offline.Local.FilePath) - assert.True(t, conf.Environments["test_env"].Offline.Local.Polling) - assert.Equal(t, 100, conf.Environments["test_env"].Offline.Local.PollInterval) - assert.True(t, conf.Environments["test_env"].Offline.UseCache) - assert.Equal(t, 200, conf.Environments["test_env"].Offline.CachePollInterval) + assert.Equal(t, "base", conf.SDKs["test_sdk"].BaseUrl) + assert.Equal(t, "sdkKey", conf.SDKs["test_sdk"].Key) + assert.Equal(t, 300, conf.SDKs["test_sdk"].PollInterval) + assert.Equal(t, "eu", conf.SDKs["test_sdk"].DataGovernance) + assert.Equal(t, log.Error, conf.SDKs["test_sdk"].Log.GetLevel()) + assert.Equal(t, "key", conf.SDKs["test_sdk"].WebhookSigningKey) + assert.Equal(t, 600, conf.SDKs["test_sdk"].WebhookSignatureValidFor) + + assert.True(t, conf.SDKs["test_sdk"].Offline.Enabled) + assert.Equal(t, log.Debug, conf.SDKs["test_sdk"].Offline.Log.GetLevel()) + assert.Equal(t, "./local.json", conf.SDKs["test_sdk"].Offline.Local.FilePath) + assert.True(t, conf.SDKs["test_sdk"].Offline.Local.Polling) + assert.Equal(t, 100, conf.SDKs["test_sdk"].Offline.Local.PollInterval) + assert.True(t, conf.SDKs["test_sdk"].Offline.UseCache) + assert.Equal(t, 200, conf.SDKs["test_sdk"].Offline.CachePollInterval) }) } diff --git a/config/env.go b/config/env.go index 1580559..83a2cc2 100644 --- a/config/env.go +++ b/config/env.go @@ -35,16 +35,16 @@ var toStringMap = func(s string) (map[string]string, error) { } func (c *Config) loadEnv() { - var envs map[string]string - readEnv(envPrefix, "ENVIRONMENTS", &envs, toStringMap) - if c.Environments == nil { - c.Environments = make(map[string]*SDKConfig, len(envs)) + var sdks map[string]string + readEnv(envPrefix, "SDKS", &sdks, toStringMap) + if c.SDKs == nil { + c.SDKs = make(map[string]*SDKConfig, len(sdks)) } - for envId, key := range envs { - prefix := concatPrefix(envPrefix, strings.ToUpper(strings.ReplaceAll(envId, "-", "_"))) + for sdkId, key := range sdks { + prefix := concatPrefix(envPrefix, strings.ToUpper(strings.ReplaceAll(sdkId, "-", "_"))) sdkConf := &SDKConfig{Key: key} sdkConf.loadEnv(prefix) - c.Environments[envId] = sdkConf + c.SDKs[sdkId] = sdkConf } c.Http.loadEnv(envPrefix) c.Grpc.loadEnv(envPrefix) diff --git a/config/env_test.go b/config/env_test.go index 32ddb2c..954e055 100644 --- a/config/env_test.go +++ b/config/env_test.go @@ -9,41 +9,41 @@ import ( ) func TestSDKConfig_ENV(t *testing.T) { - t.Setenv("CONFIGCAT_ENVIRONMENTS", `{"env1": "sdkKey"}`) - t.Setenv("CONFIGCAT_ENV1_BASE_URL", "base") - t.Setenv("CONFIGCAT_ENV1_KEY", "sdkKey") - t.Setenv("CONFIGCAT_ENV1_POLL_INTERVAL", "300") - t.Setenv("CONFIGCAT_ENV1_DATA_GOVERNANCE", "eu") - t.Setenv("CONFIGCAT_ENV1_LOG_LEVEL", "error") - - t.Setenv("CONFIGCAT_ENV1_OFFLINE_ENABLED", "true") - t.Setenv("CONFIGCAT_ENV1_OFFLINE_LOG_LEVEL", "debug") - t.Setenv("CONFIGCAT_ENV1_OFFLINE_LOCAL_FILE_PATH", "./local.json") - t.Setenv("CONFIGCAT_ENV1_OFFLINE_LOCAL_POLLING", "true") - t.Setenv("CONFIGCAT_ENV1_OFFLINE_LOCAL_POLL_INTERVAL", "100") - t.Setenv("CONFIGCAT_ENV1_OFFLINE_USE_CACHE", "true") - t.Setenv("CONFIGCAT_ENV1_OFFLINE_CACHE_POLL_INTERVAL", "200") - t.Setenv("CONFIGCAT_ENV1_WEBHOOK_SIGNING_KEY", "key") - t.Setenv("CONFIGCAT_ENV1_WEBHOOK_SIGNATURE_VALID_FOR", "600") + t.Setenv("CONFIGCAT_SDKS", `{"sdk1": "sdkKey"}`) + t.Setenv("CONFIGCAT_SDK1_BASE_URL", "base") + t.Setenv("CONFIGCAT_SDK1_KEY", "sdkKey") + t.Setenv("CONFIGCAT_SDK1_POLL_INTERVAL", "300") + t.Setenv("CONFIGCAT_SDK1_DATA_GOVERNANCE", "eu") + t.Setenv("CONFIGCAT_SDK1_LOG_LEVEL", "error") + + t.Setenv("CONFIGCAT_SDK1_OFFLINE_ENABLED", "true") + t.Setenv("CONFIGCAT_SDK1_OFFLINE_LOG_LEVEL", "debug") + t.Setenv("CONFIGCAT_SDK1_OFFLINE_LOCAL_FILE_PATH", "./local.json") + t.Setenv("CONFIGCAT_SDK1_OFFLINE_LOCAL_POLLING", "true") + t.Setenv("CONFIGCAT_SDK1_OFFLINE_LOCAL_POLL_INTERVAL", "100") + t.Setenv("CONFIGCAT_SDK1_OFFLINE_USE_CACHE", "true") + t.Setenv("CONFIGCAT_SDK1_OFFLINE_CACHE_POLL_INTERVAL", "200") + t.Setenv("CONFIGCAT_SDK1_WEBHOOK_SIGNING_KEY", "key") + t.Setenv("CONFIGCAT_SDK1_WEBHOOK_SIGNATURE_VALID_FOR", "600") conf, err := LoadConfigFromFileAndEnvironment("") require.NoError(t, err) - assert.Equal(t, "base", conf.Environments["env1"].BaseUrl) - assert.Equal(t, "sdkKey", conf.Environments["env1"].Key) - assert.Equal(t, 300, conf.Environments["env1"].PollInterval) - assert.Equal(t, "eu", conf.Environments["env1"].DataGovernance) - assert.Equal(t, log.Error, conf.Environments["env1"].Log.GetLevel()) - - assert.True(t, conf.Environments["env1"].Offline.Enabled) - assert.Equal(t, log.Debug, conf.Environments["env1"].Offline.Log.GetLevel()) - assert.Equal(t, "./local.json", conf.Environments["env1"].Offline.Local.FilePath) - assert.True(t, conf.Environments["env1"].Offline.Local.Polling) - assert.Equal(t, 100, conf.Environments["env1"].Offline.Local.PollInterval) - assert.True(t, conf.Environments["env1"].Offline.UseCache) - assert.Equal(t, 200, conf.Environments["env1"].Offline.CachePollInterval) - assert.Equal(t, "key", conf.Environments["env1"].WebhookSigningKey) - assert.Equal(t, 600, conf.Environments["env1"].WebhookSignatureValidFor) + assert.Equal(t, "base", conf.SDKs["sdk1"].BaseUrl) + assert.Equal(t, "sdkKey", conf.SDKs["sdk1"].Key) + assert.Equal(t, 300, conf.SDKs["sdk1"].PollInterval) + assert.Equal(t, "eu", conf.SDKs["sdk1"].DataGovernance) + assert.Equal(t, log.Error, conf.SDKs["sdk1"].Log.GetLevel()) + + assert.True(t, conf.SDKs["sdk1"].Offline.Enabled) + assert.Equal(t, log.Debug, conf.SDKs["sdk1"].Offline.Log.GetLevel()) + assert.Equal(t, "./local.json", conf.SDKs["sdk1"].Offline.Local.FilePath) + assert.True(t, conf.SDKs["sdk1"].Offline.Local.Polling) + assert.Equal(t, 100, conf.SDKs["sdk1"].Offline.Local.PollInterval) + assert.True(t, conf.SDKs["sdk1"].Offline.UseCache) + assert.Equal(t, 200, conf.SDKs["sdk1"].Offline.CachePollInterval) + assert.Equal(t, "key", conf.SDKs["sdk1"].WebhookSigningKey) + assert.Equal(t, 600, conf.SDKs["sdk1"].WebhookSignatureValidFor) } func TestCacheConfig_ENV(t *testing.T) { diff --git a/config/validate.go b/config/validate.go index b650514..57fbbf7 100644 --- a/config/validate.go +++ b/config/validate.go @@ -7,10 +7,10 @@ import ( ) func (c *Config) Validate() error { - if len(c.Environments) == 0 { + if len(c.SDKs) == 0 { return fmt.Errorf("sdk: at least 1 environment with an SDK key required") } - for id, env := range c.Environments { + for id, env := range c.SDKs { if err := env.validate(&c.Cache, id); err != nil { return err } diff --git a/config/validate_test.go b/config/validate_test.go index 3daa358..de0c391 100644 --- a/config/validate_test.go +++ b/config/validate_test.go @@ -12,86 +12,86 @@ func TestConfig_Validate(t *testing.T) { require.ErrorContains(t, conf.Validate(), "sdk: at least 1 environment with an SDK key required") }) t.Run("missing sdk key", func(t *testing.T) { - conf := Config{Environments: map[string]*SDKConfig{"env1": {}}} + conf := Config{SDKs: map[string]*SDKConfig{"env1": {}}} require.ErrorContains(t, conf.Validate(), "sdk-env1: SDK key is required") }) t.Run("invalid data governance", func(t *testing.T) { - conf := Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key", DataGovernance: "inv"}}} + conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key", DataGovernance: "inv"}}} require.ErrorContains(t, conf.Validate(), "sdk-env1: invalid data governance value, it must be 'global' or 'eu'") }) t.Run("offline invalid file path", func(t *testing.T) { - conf := Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key", Offline: OfflineConfig{Enabled: true, Local: LocalConfig{FilePath: "nonexisting"}}}}} + conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key", Offline: OfflineConfig{Enabled: true, Local: LocalConfig{FilePath: "nonexisting"}}}}} require.ErrorContains(t, conf.Validate(), "sdk-env1: couldn't find the local file") }) t.Run("offline file polling invalid poll interval", func(t *testing.T) { utils.UseTempFile("", func(path string) { - conf := Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key", Offline: OfflineConfig{Enabled: true, Local: LocalConfig{FilePath: path, Polling: true, PollInterval: 0}}}}} + conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key", Offline: OfflineConfig{Enabled: true, Local: LocalConfig{FilePath: path, Polling: true, PollInterval: 0}}}}} require.ErrorContains(t, conf.Validate(), "sdk-env1: local file poll interval must be greater than 1 seconds") }) }) t.Run("offline enabled without file and cache", func(t *testing.T) { - conf := Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key", Offline: OfflineConfig{Enabled: true}}}} + conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key", Offline: OfflineConfig{Enabled: true}}}} require.ErrorContains(t, conf.Validate(), "sdk-env1: offline mode requires either a configured cache or a local file") }) t.Run("offline both local file and cache", func(t *testing.T) { - conf := Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key", Offline: OfflineConfig{Enabled: true, UseCache: true, Local: LocalConfig{FilePath: "file"}}}}} + conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key", Offline: OfflineConfig{Enabled: true, UseCache: true, Local: LocalConfig{FilePath: "file"}}}}} require.ErrorContains(t, conf.Validate(), "sdk-env1: can't use both local file and cache for offline mode") }) t.Run("offline cache without redis", func(t *testing.T) { - conf := Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key", Offline: OfflineConfig{Enabled: true, UseCache: true}}}} + conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key", Offline: OfflineConfig{Enabled: true, UseCache: true}}}} require.ErrorContains(t, conf.Validate(), "sdk-env1: offline mode enabled with cache, but no cache is configured") }) t.Run("offline cache invalid poll interval", func(t *testing.T) { - conf := Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key", Offline: OfflineConfig{Enabled: true, UseCache: true, CachePollInterval: 0}}}, Cache: CacheConfig{Redis: RedisConfig{}}} + conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key", Offline: OfflineConfig{Enabled: true, UseCache: true, CachePollInterval: 0}}}, Cache: CacheConfig{Redis: RedisConfig{}}} require.ErrorContains(t, conf.Validate(), "sdk-env1: offline mode enabled with cache, but no cache is configured") }) t.Run("redis enabled without addresses", func(t *testing.T) { - conf := Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key"}}, Cache: CacheConfig{Redis: RedisConfig{Enabled: true}}} + conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, Cache: CacheConfig{Redis: RedisConfig{Enabled: true}}} require.ErrorContains(t, conf.Validate(), "redis: at least 1 server address required") }) t.Run("redis invalid tls config", func(t *testing.T) { - conf := Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key"}}, Cache: CacheConfig{Redis: RedisConfig{Enabled: true, Addresses: []string{"localhost"}, Tls: TlsConfig{Enabled: true, Certificates: []CertConfig{{Key: "key"}}}}}} + conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, Cache: CacheConfig{Redis: RedisConfig{Enabled: true, Addresses: []string{"localhost"}, Tls: TlsConfig{Enabled: true, Certificates: []CertConfig{{Key: "key"}}}}}} require.ErrorContains(t, conf.Validate(), "tls: both TLS cert and key file required") - conf = Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key"}}, Cache: CacheConfig{Redis: RedisConfig{Enabled: true, Addresses: []string{"localhost"}, Tls: TlsConfig{Enabled: true, Certificates: []CertConfig{{Cert: "cert"}}}}}} + conf = Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, Cache: CacheConfig{Redis: RedisConfig{Enabled: true, Addresses: []string{"localhost"}, Tls: TlsConfig{Enabled: true, Certificates: []CertConfig{{Cert: "cert"}}}}}} require.ErrorContains(t, conf.Validate(), "tls: both TLS cert and key file required") }) t.Run("influx db validate", func(t *testing.T) { - conf := Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key"}}, EvalStats: EvalStatsConfig{InfluxDb: InfluxDbConfig{Enabled: true, Organization: "org", AuthToken: "auth", Bucket: "bucket"}}} + conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, EvalStats: EvalStatsConfig{InfluxDb: InfluxDbConfig{Enabled: true, Organization: "org", AuthToken: "auth", Bucket: "bucket"}}} require.ErrorContains(t, conf.Validate(), "influxdb: URL is required") - conf = Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key"}}, EvalStats: EvalStatsConfig{InfluxDb: InfluxDbConfig{Enabled: true, Organization: "org", AuthToken: "auth", Url: "url"}}} + conf = Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, EvalStats: EvalStatsConfig{InfluxDb: InfluxDbConfig{Enabled: true, Organization: "org", AuthToken: "auth", Url: "url"}}} require.ErrorContains(t, conf.Validate(), "influxdb: bucket is required") - conf = Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key"}}, EvalStats: EvalStatsConfig{InfluxDb: InfluxDbConfig{Enabled: true, Organization: "org", Bucket: "bucket", Url: "url"}}} + conf = Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, EvalStats: EvalStatsConfig{InfluxDb: InfluxDbConfig{Enabled: true, Organization: "org", Bucket: "bucket", Url: "url"}}} require.ErrorContains(t, conf.Validate(), "influxdb: auth token is required") - conf = Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key"}}, EvalStats: EvalStatsConfig{InfluxDb: InfluxDbConfig{Enabled: true, AuthToken: "auth", Bucket: "bucket", Url: "url"}}} + conf = Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, EvalStats: EvalStatsConfig{InfluxDb: InfluxDbConfig{Enabled: true, AuthToken: "auth", Bucket: "bucket", Url: "url"}}} require.ErrorContains(t, conf.Validate(), "influxdb: organization is required") }) t.Run("influx db tls validate", func(t *testing.T) { - conf := Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key"}}, EvalStats: EvalStatsConfig{InfluxDb: InfluxDbConfig{Enabled: true, Organization: "org", AuthToken: "auth", Bucket: "bucket", Url: "url", Tls: TlsConfig{Enabled: true, Certificates: []CertConfig{{Key: "key"}}}}}} + conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, EvalStats: EvalStatsConfig{InfluxDb: InfluxDbConfig{Enabled: true, Organization: "org", AuthToken: "auth", Bucket: "bucket", Url: "url", Tls: TlsConfig{Enabled: true, Certificates: []CertConfig{{Key: "key"}}}}}} require.ErrorContains(t, conf.Validate(), "tls: both TLS cert and key file required") - conf = Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key"}}, EvalStats: EvalStatsConfig{InfluxDb: InfluxDbConfig{Enabled: true, Organization: "org", AuthToken: "auth", Bucket: "bucket", Url: "url", Tls: TlsConfig{Enabled: true, Certificates: []CertConfig{{Cert: "cert"}}}}}} + conf = Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, EvalStats: EvalStatsConfig{InfluxDb: InfluxDbConfig{Enabled: true, Organization: "org", AuthToken: "auth", Bucket: "bucket", Url: "url", Tls: TlsConfig{Enabled: true, Certificates: []CertConfig{{Cert: "cert"}}}}}} require.ErrorContains(t, conf.Validate(), "tls: both TLS cert and key file required") }) t.Run("webhook signature invalid validity time", func(t *testing.T) { - conf := Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key", WebhookSigningKey: "key", WebhookSignatureValidFor: 2}}} + conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key", WebhookSigningKey: "key", WebhookSignatureValidFor: 2}}} require.ErrorContains(t, conf.Validate(), "sdk-env1: webhook signature validity check must be greater than 5 seconds") }) t.Run("webhook invalid auth", func(t *testing.T) { - conf := Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key"}}, Http: HttpConfig{Webhook: WebhookConfig{Enabled: true, Auth: AuthConfig{User: "user"}}}} + conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, Http: HttpConfig{Webhook: WebhookConfig{Enabled: true, Auth: AuthConfig{User: "user"}}}} require.ErrorContains(t, conf.Validate(), "webhook: both basic auth user and password required") - conf = Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key"}}, Http: HttpConfig{Webhook: WebhookConfig{Enabled: true, Auth: AuthConfig{Password: "pass"}}}} + conf = Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, Http: HttpConfig{Webhook: WebhookConfig{Enabled: true, Auth: AuthConfig{Password: "pass"}}}} require.ErrorContains(t, conf.Validate(), "webhook: both basic auth user and password required") }) t.Run("http invalid tls config", func(t *testing.T) { - conf := Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key"}}, Tls: TlsConfig{Enabled: true, Certificates: []CertConfig{{Key: "key"}}}} + conf := Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, Tls: TlsConfig{Enabled: true, Certificates: []CertConfig{{Key: "key"}}}} require.ErrorContains(t, conf.Validate(), "tls: both TLS cert and key file required") - conf = Config{Environments: map[string]*SDKConfig{"env1": {Key: "Key"}}, Tls: TlsConfig{Enabled: true, Certificates: []CertConfig{{Cert: "cert"}}}} + conf = Config{SDKs: map[string]*SDKConfig{"env1": {Key: "Key"}}, Tls: TlsConfig{Enabled: true, Certificates: []CertConfig{{Cert: "cert"}}}} require.ErrorContains(t, conf.Validate(), "tls: both TLS cert and key file required") }) } diff --git a/docker-compose.yml b/docker-compose.yml index d16666b..50ce4e8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,17 +23,17 @@ services: volumes: - ./internal/resources/cert:/cert environment: - - CONFIGCAT_ENVIRONMENTS={"env1":"XxPbCKmzIUGORk4vsufpzw/iC_KABprDEueeQs3yovVnQ", "env2":"XxPbCKmzIUGORk4vsufpzw/6ft7XQudcEuIXY49grZM9w"} - - CONFIGCAT_ENV1_BASE_URL=https://test-cdn-global.configcat.com - - CONFIGCAT_ENV1_POLL_INTERVAL=300 - - CONFIGCAT_ENV1_LOG_LEVEL=error - - CONFIGCAT_ENV1_WEBHOOK_SIGNING_KEY=configcat_whsk_Dj59sEWxRmm+84izQ8Cbn9o4Pnjz7E+/hxcmyfEVT+A= - - CONFIGCAT_ENV2_BASE_URL=https://test-cdn-global.configcat.com - - CONFIGCAT_ENV2_POLL_INTERVAL=300 - - CONFIGCAT_ENV2_WEBHOOK_SIGNING_KEY=configcat_whsk_a8w2b38Ofhs0rzXbZhNCvPTeTeUxmerTBy9PzMCX6+E= -# - CONFIGCAT_ENV2_OFFLINE_ENABLED=true -# - CONFIGCAT_ENV2_OFFLINE_USE_CACHE=true - - CONFIGCAT_ENV2_LOG_LEVEL=error + - CONFIGCAT_SDKS={"sdk1":"XxPbCKmzIUGORk4vsufpzw/iC_KABprDEueeQs3yovVnQ", "sdk2":"XxPbCKmzIUGORk4vsufpzw/6ft7XQudcEuIXY49grZM9w"} + - CONFIGCAT_SDK1_BASE_URL=https://test-cdn-global.configcat.com + - CONFIGCAT_SDK1_POLL_INTERVAL=300 + - CONFIGCAT_SDK1_LOG_LEVEL=error + - CONFIGCAT_SDK1_WEBHOOK_SIGNING_KEY=configcat_whsk_Dj59sEWxRmm+84izQ8Cbn9o4Pnjz7E+/hxcmyfEVT+A= + - CONFIGCAT_SDK2_BASE_URL=https://test-cdn-global.configcat.com + - CONFIGCAT_SDK2_POLL_INTERVAL=300 + - CONFIGCAT_SDK2_WEBHOOK_SIGNING_KEY=configcat_whsk_a8w2b38Ofhs0rzXbZhNCvPTeTeUxmerTBy9PzMCX6+E= +# - CONFIGCAT_SDK2_OFFLINE_ENABLED=true +# - CONFIGCAT_SDK2_OFFLINE_USE_CACHE=true + - CONFIGCAT_SDK2_LOG_LEVEL=error - CONFIGCAT_CACHE_REDIS_ENABLED=true - CONFIGCAT_CACHE_REDIS_ADDRESSES=["redis:6379"] - CONFIGCAT_TLS_ENABLED=true diff --git a/internal/resources/config.yml b/internal/resources/config.yml index 0d99261..2b6d621 100644 --- a/internal/resources/config.yml +++ b/internal/resources/config.yml @@ -1,5 +1,5 @@ -environments: - env1: +sdks: + sdk1: base_url: "https://test-cdn-global.configcat.com" key: "XxPbCKmzIUGORk4vsufpzw/iC_KABprDEueeQs3yovVnQ" poll_interval: 300 diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 2637f16..ca8198a 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -75,8 +75,8 @@ func Obfuscate(str string, clearLen int) string { return strings.Repeat("*", utf8.RuneCountInString(toObfuscate)) + str[l-clearLen:l] } -func AddEnvContextParam(r *http.Request) { - params := httprouter.Params{httprouter.Param{Key: "env", Value: "test"}} +func AddSdkIdContextParam(r *http.Request) { + params := httprouter.Params{httprouter.Param{Key: "sdkId", Value: "test"}} ctx := context.WithValue(context.Background(), httprouter.ParamsKey, params) *r = *r.WithContext(ctx) } diff --git a/main.go b/main.go index 5842ff3..a9dbd6d 100644 --- a/main.go +++ b/main.go @@ -53,7 +53,7 @@ func main() { statusReporter := status.NewReporter(&conf) sdkClients := make(map[string]sdk.Client) - for key, env := range conf.Environments { + for key, env := range conf.SDKs { sdkClients[key] = sdk.NewClient(&sdk.Context{ SDKConf: env, EvalReporter: evalReporter, diff --git a/status/mware_test.go b/status/mware_test.go index d4e0636..aa6ef4c 100644 --- a/status/mware_test.go +++ b/status/mware_test.go @@ -10,7 +10,7 @@ import ( func TestInterceptSdk(t *testing.T) { t.Run("ok", func(t *testing.T) { - reporter := NewReporter(&config.Config{Environments: map[string]*config.SDKConfig{"test": {}}}).(*reporter) + reporter := NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"test": {}}}).(*reporter) repSrv := httptest.NewServer(reporter.HttpHandler()) h := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { writer.WriteHeader(http.StatusOK) @@ -33,7 +33,7 @@ func TestInterceptSdk(t *testing.T) { assert.Equal(t, 0, len(stat.Cache.Records)) }) t.Run("not modified", func(t *testing.T) { - reporter := NewReporter(&config.Config{Environments: map[string]*config.SDKConfig{"test": {}}}).(*reporter) + reporter := NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"test": {}}}).(*reporter) repSrv := httptest.NewServer(reporter.HttpHandler()) h := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { writer.WriteHeader(http.StatusNotModified) @@ -56,7 +56,7 @@ func TestInterceptSdk(t *testing.T) { assert.Equal(t, 0, len(stat.Cache.Records)) }) t.Run("error", func(t *testing.T) { - reporter := NewReporter(&config.Config{Environments: map[string]*config.SDKConfig{"test": {}}}).(*reporter) + reporter := NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"test": {}}}).(*reporter) repSrv := httptest.NewServer(reporter.HttpHandler()) h := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { writer.WriteHeader(http.StatusBadRequest) diff --git a/status/status.go b/status/status.go index 7a8f37d..512ddf2 100644 --- a/status/status.go +++ b/status/status.go @@ -91,8 +91,8 @@ func NewReporter(conf *config.Config) Reporter { }, }, } - envs := make(map[string]*SdkStatus, len(conf.Environments)) - for key, env := range conf.Environments { + envs := make(map[string]*SdkStatus, len(conf.SDKs)) + for key, env := range conf.SDKs { status := &SdkStatus{ Mode: Online, SdkKey: utils.Obfuscate(env.Key, 5), @@ -148,7 +148,7 @@ func (r *reporter) getStatus() Status { current := r.status overallStatus := Healthy - for key := range r.conf.Environments { + for key := range r.conf.SDKs { if sdk, ok := r.records[key]; ok { stat := current.Environments[key].Source.Status rec, stat := r.checkStatus(sdk) diff --git a/status/status_test.go b/status/status_test.go index 3f9f8d0..fa6fd26 100644 --- a/status/status_test.go +++ b/status/status_test.go @@ -13,7 +13,7 @@ import ( func TestReporter_Online(t *testing.T) { t.Run("ok", func(t *testing.T) { - reporter := NewReporter(&config.Config{Environments: map[string]*config.SDKConfig{"t": {}}}) + reporter := NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"t": {}}}) srv := httptest.NewServer(reporter.HttpHandler()) reporter.ReportOk("t", "") stat := readStatus(srv.URL) @@ -28,7 +28,7 @@ func TestReporter_Online(t *testing.T) { }) t.Run("degraded after 2 errors, then ok again", func(t *testing.T) { - reporter := NewReporter(&config.Config{Environments: map[string]*config.SDKConfig{"t": {}}}) + reporter := NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"t": {}}}) srv := httptest.NewServer(reporter.HttpHandler()) reporter.ReportError("t", fmt.Errorf("")) reporter.ReportError("t", fmt.Errorf("")) @@ -54,7 +54,7 @@ func TestReporter_Online(t *testing.T) { assert.Equal(t, 0, len(stat.Cache.Records)) }) t.Run("max 5 records", func(t *testing.T) { - reporter := NewReporter(&config.Config{Environments: map[string]*config.SDKConfig{"t": {}}}) + reporter := NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"t": {}}}) srv := httptest.NewServer(reporter.HttpHandler()) reporter.ReportOk("t", "m1") reporter.ReportOk("t", "m2") @@ -75,7 +75,7 @@ func TestReporter_Online(t *testing.T) { func TestReporter_Offline(t *testing.T) { t.Run("file", func(t *testing.T) { - reporter := NewReporter(&config.Config{Environments: map[string]*config.SDKConfig{"t": {Offline: config.OfflineConfig{Enabled: true, Local: config.LocalConfig{FilePath: "test"}}}}}) + reporter := NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"t": {Offline: config.OfflineConfig{Enabled: true, Local: config.LocalConfig{FilePath: "test"}}}}}) srv := httptest.NewServer(reporter.HttpHandler()) reporter.ReportOk("t", "") stat := readStatus(srv.URL) @@ -89,7 +89,7 @@ func TestReporter_Offline(t *testing.T) { assert.Equal(t, 0, len(stat.Cache.Records)) }) t.Run("cache invalid", func(t *testing.T) { - reporter := NewReporter(&config.Config{Environments: map[string]*config.SDKConfig{"t": {Offline: config.OfflineConfig{Enabled: true, UseCache: true}}}}) + reporter := NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"t": {Offline: config.OfflineConfig{Enabled: true, UseCache: true}}}}) srv := httptest.NewServer(reporter.HttpHandler()) stat := readStatus(srv.URL) @@ -102,7 +102,7 @@ func TestReporter_Offline(t *testing.T) { assert.Equal(t, 0, len(stat.Cache.Records)) }) t.Run("cache valid", func(t *testing.T) { - reporter := NewReporter(&config.Config{Environments: map[string]*config.SDKConfig{"t": {Offline: config.OfflineConfig{Enabled: true, UseCache: true}}}, Cache: config.CacheConfig{Redis: config.RedisConfig{Enabled: true}}}) + reporter := NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"t": {Offline: config.OfflineConfig{Enabled: true, UseCache: true}}}, Cache: config.CacheConfig{Redis: config.RedisConfig{Enabled: true}}}) srv := httptest.NewServer(reporter.HttpHandler()) reporter.ReportOk("t", "") reporter.ReportOk(Cache, "") @@ -119,7 +119,7 @@ func TestReporter_Offline(t *testing.T) { } func TestReporter_StatusCopy(t *testing.T) { - reporter := NewReporter(&config.Config{Environments: map[string]*config.SDKConfig{"t": {}}}).(*reporter) + reporter := NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"t": {}}}).(*reporter) reporter.ReportError("t", fmt.Errorf("")) stat := reporter.getStatus() @@ -129,7 +129,7 @@ func TestReporter_StatusCopy(t *testing.T) { func TestReporter_Degraded_Calc(t *testing.T) { t.Run("1 record, 1 error", func(t *testing.T) { - reporter := NewReporter(&config.Config{Environments: map[string]*config.SDKConfig{"t": {}}}).(*reporter) + reporter := NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"t": {}}}).(*reporter) reporter.ReportError("t", fmt.Errorf("")) stat := reporter.getStatus() @@ -137,7 +137,7 @@ func TestReporter_Degraded_Calc(t *testing.T) { assert.Equal(t, Degraded, stat.Environments["t"].Source.Status) }) t.Run("2 records, 1 error then 1 ok", func(t *testing.T) { - reporter := NewReporter(&config.Config{Environments: map[string]*config.SDKConfig{"t": {}}}).(*reporter) + reporter := NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"t": {}}}).(*reporter) reporter.ReportError("t", fmt.Errorf("")) reporter.ReportOk("t", "") stat := reporter.getStatus() @@ -146,7 +146,7 @@ func TestReporter_Degraded_Calc(t *testing.T) { assert.Equal(t, Healthy, stat.Environments["t"].Source.Status) }) t.Run("2 records, 1 ok then 1 error", func(t *testing.T) { - reporter := NewReporter(&config.Config{Environments: map[string]*config.SDKConfig{"t": {}}}).(*reporter) + reporter := NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"t": {}}}).(*reporter) reporter.ReportOk("t", "") reporter.ReportError("t", fmt.Errorf("")) stat := reporter.getStatus() @@ -155,7 +155,7 @@ func TestReporter_Degraded_Calc(t *testing.T) { assert.Equal(t, Healthy, stat.Environments["t"].Source.Status) }) t.Run("3 records, 1 ok then 2 errors", func(t *testing.T) { - reporter := NewReporter(&config.Config{Environments: map[string]*config.SDKConfig{"t": {}}}).(*reporter) + reporter := NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"t": {}}}).(*reporter) reporter.ReportOk("t", "") reporter.ReportError("t", fmt.Errorf("")) reporter.ReportError("t", fmt.Errorf("")) @@ -165,7 +165,7 @@ func TestReporter_Degraded_Calc(t *testing.T) { assert.Equal(t, Degraded, stat.Environments["t"].Source.Status) }) t.Run("3 records, 1 ok then 1 error then 1 ok", func(t *testing.T) { - reporter := NewReporter(&config.Config{Environments: map[string]*config.SDKConfig{"t": {}}}).(*reporter) + reporter := NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"t": {}}}).(*reporter) reporter.ReportOk("t", "") reporter.ReportError("t", fmt.Errorf("")) reporter.ReportOk("t", "") @@ -175,7 +175,7 @@ func TestReporter_Degraded_Calc(t *testing.T) { assert.Equal(t, Healthy, stat.Environments["t"].Source.Status) }) t.Run("3 records, 1 error then 1 ok then 1 error", func(t *testing.T) { - reporter := NewReporter(&config.Config{Environments: map[string]*config.SDKConfig{"t": {}}}).(*reporter) + reporter := NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"t": {}}}).(*reporter) reporter.ReportError("t", fmt.Errorf("")) reporter.ReportOk("t", "") reporter.ReportError("t", fmt.Errorf("")) @@ -185,7 +185,7 @@ func TestReporter_Degraded_Calc(t *testing.T) { assert.Equal(t, Healthy, stat.Environments["t"].Source.Status) }) t.Run("2 envs 1 degraded", func(t *testing.T) { - reporter := NewReporter(&config.Config{Environments: map[string]*config.SDKConfig{"t1": {}, "t2": {}}}).(*reporter) + reporter := NewReporter(&config.Config{SDKs: map[string]*config.SDKConfig{"t1": {}, "t2": {}}}).(*reporter) reporter.ReportError("t1", fmt.Errorf("")) reporter.ReportOk("t2", "") stat := reporter.getStatus() diff --git a/web/api/api.go b/web/api/api.go index b0989f8..2364f08 100644 --- a/web/api/api.go +++ b/web/api/api.go @@ -124,15 +124,19 @@ func (s *Server) Refresh(w http.ResponseWriter, r *http.Request) { } } +func (s *Server) ICanHasCoffee(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusTeapot) +} + func (s *Server) getSDKClient(ctx context.Context) (sdk.Client, error) { vars := httprouter.ParamsFromContext(ctx) - env := vars.ByName("env") - if env == "" { - return nil, fmt.Errorf("'env' path parameter must be set") + sdkId := vars.ByName("sdkId") + if sdkId == "" { + return nil, fmt.Errorf("'sdkId' path parameter must be set") } - sdkClient, ok := s.sdkClients[env] + sdkClient, ok := s.sdkClients[sdkId] if !ok { - return nil, fmt.Errorf("invalid environment identifier: '%s'", env) + return nil, fmt.Errorf("invalid SDK identifier: '%s'", sdkId) } return sdkClient, nil } diff --git a/web/api/api_test.go b/web/api/api_test.go index 01f3c24..4af84c2 100644 --- a/web/api/api_test.go +++ b/web/api/api_test.go @@ -21,7 +21,7 @@ func TestAPI_Eval(t *testing.T) { req, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(`{"key":"flag"}`)) srv := newServer(t, config.ApiConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.Eval(res, req) assert.Equal(t, 200, res.Code) @@ -32,7 +32,7 @@ func TestAPI_Eval(t *testing.T) { req, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(`{"key":"flag"}`)) srv := newErrorServer(t, config.ApiConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.Eval(res, req) assert.Equal(t, http.StatusInternalServerError, res.Code) @@ -43,7 +43,7 @@ func TestAPI_Eval(t *testing.T) { req, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(`{"key":"flag"}`)) srv := newOfflineServer(t, path, config.ApiConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.Eval(res, req) assert.Equal(t, http.StatusOK, res.Code) @@ -56,7 +56,7 @@ func TestAPI_Eval(t *testing.T) { req, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(`{"key":"flag"}`)) srv := newOfflineServer(t, path, config.ApiConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.Eval(res, req) assert.Equal(t, http.StatusInternalServerError, res.Code) @@ -70,7 +70,7 @@ func TestAPI_EvalAll(t *testing.T) { req, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(`{"key":"flag"}`)) srv := newServer(t, config.ApiConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.EvalAll(res, req) assert.Equal(t, 200, res.Code) @@ -81,7 +81,7 @@ func TestAPI_EvalAll(t *testing.T) { req, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(`{"key":"flag"}`)) srv := newErrorServer(t, config.ApiConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.EvalAll(res, req) assert.Equal(t, http.StatusOK, res.Code) @@ -93,7 +93,7 @@ func TestAPI_EvalAll(t *testing.T) { req, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(`{"key":"flag"}`)) srv := newOfflineServer(t, path, config.ApiConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.EvalAll(res, req) assert.Equal(t, http.StatusOK, res.Code) @@ -106,7 +106,7 @@ func TestAPI_EvalAll(t *testing.T) { req, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(`{"key":"flag"}`)) srv := newOfflineServer(t, path, config.ApiConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.EvalAll(res, req) assert.Equal(t, http.StatusOK, res.Code) @@ -121,7 +121,7 @@ func TestAPI_Keys(t *testing.T) { req, _ := http.NewRequest(http.MethodGet, "/", http.NoBody) srv := newServer(t, config.ApiConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.Keys(res, req) assert.Equal(t, 200, res.Code) @@ -132,7 +132,7 @@ func TestAPI_Keys(t *testing.T) { req, _ := http.NewRequest(http.MethodGet, "/", http.NoBody) srv := newErrorServer(t, config.ApiConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.Keys(res, req) assert.Equal(t, http.StatusOK, res.Code) @@ -144,7 +144,7 @@ func TestAPI_Keys(t *testing.T) { req, _ := http.NewRequest(http.MethodGet, "/", http.NoBody) srv := newOfflineServer(t, path, config.ApiConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.Keys(res, req) assert.Equal(t, http.StatusOK, res.Code) @@ -157,7 +157,7 @@ func TestAPI_Keys(t *testing.T) { req, _ := http.NewRequest(http.MethodGet, "/", http.NoBody) srv := newOfflineServer(t, path, config.ApiConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.Keys(res, req) assert.Equal(t, http.StatusOK, res.Code) @@ -179,7 +179,7 @@ func TestAPI_Refresh(t *testing.T) { res := httptest.NewRecorder() req, _ := http.NewRequest(http.MethodPost, "/", strings.NewReader(`{"key":"flag"}`)) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.Eval(res, req) assert.Equal(t, http.StatusOK, res.Code) @@ -192,12 +192,12 @@ func TestAPI_Refresh(t *testing.T) { }) req = &http.Request{Method: http.MethodPost} - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.Refresh(httptest.NewRecorder(), req) time.Sleep(100 * time.Millisecond) res = httptest.NewRecorder() req, _ = http.NewRequest(http.MethodPost, "/", strings.NewReader(`{"key":"flag"}`)) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.Eval(res, req) assert.Equal(t, http.StatusOK, res.Code) diff --git a/web/cdnproxy/cdnproxy.go b/web/cdnproxy/cdnproxy.go index 64b4bab..bf1cbbc 100644 --- a/web/cdnproxy/cdnproxy.go +++ b/web/cdnproxy/cdnproxy.go @@ -46,13 +46,13 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (s *Server) getSDKClient(ctx context.Context) (sdk.Client, error) { vars := httprouter.ParamsFromContext(ctx) - env := vars.ByName("env") - if env == "" { - return nil, fmt.Errorf("'env' path parameter must be set") + sdkId := vars.ByName("sdkId") + if sdkId == "" { + return nil, fmt.Errorf("'sdkId' path parameter must be set") } - sdkClient, ok := s.sdkClients[env] + sdkClient, ok := s.sdkClients[sdkId] if !ok { - return nil, fmt.Errorf("invalid environment identifier: '%s'", env) + return nil, fmt.Errorf("invalid SDK identifier: '%s'", sdkId) } return sdkClient, nil } diff --git a/web/cdnproxy/cdnproxy_test.go b/web/cdnproxy/cdnproxy_test.go index cceae73..890c763 100644 --- a/web/cdnproxy/cdnproxy_test.go +++ b/web/cdnproxy/cdnproxy_test.go @@ -19,7 +19,7 @@ func TestProxy_Get(t *testing.T) { req := &http.Request{Method: http.MethodGet} srv := newServer(t, config.CdnProxyConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.ServeHTTP(res, req) assert.Equal(t, http.StatusOK, res.Code) @@ -30,7 +30,7 @@ func TestProxy_Get(t *testing.T) { req := &http.Request{Method: http.MethodGet} srv := newErrorServer(t, config.CdnProxyConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.ServeHTTP(res, req) assert.Equal(t, http.StatusOK, res.Code) @@ -42,7 +42,7 @@ func TestProxy_Get(t *testing.T) { req := &http.Request{Method: http.MethodGet} srv := newOfflineServer(t, path, config.CdnProxyConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.ServeHTTP(res, req) assert.Equal(t, http.StatusOK, res.Code) @@ -55,7 +55,7 @@ func TestProxy_Get(t *testing.T) { req := &http.Request{Method: http.MethodGet} srv := newOfflineServer(t, path, config.CdnProxyConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.ServeHTTP(res, req) assert.Equal(t, http.StatusOK, res.Code) @@ -67,7 +67,7 @@ func TestProxy_Get(t *testing.T) { req := &http.Request{Method: http.MethodGet} srv := newServer(t, config.CdnProxyConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.ServeHTTP(res, req) assert.Equal(t, http.StatusOK, res.Code) @@ -78,7 +78,7 @@ func TestProxy_Get(t *testing.T) { res = httptest.NewRecorder() req = &http.Request{Method: http.MethodGet, Header: map[string][]string{}} req.Header.Set("If-None-Match", etag) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.ServeHTTP(res, req) assert.Equal(t, http.StatusNotModified, res.Code) @@ -89,7 +89,7 @@ func TestProxy_Get(t *testing.T) { req := &http.Request{Method: http.MethodGet} srv, h, key := newServerWithHandler(t, config.CdnProxyConfig{Enabled: true}) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.ServeHTTP(res, req) assert.Equal(t, http.StatusOK, res.Code) @@ -100,7 +100,7 @@ func TestProxy_Get(t *testing.T) { res = httptest.NewRecorder() req = &http.Request{Method: http.MethodGet, Header: map[string][]string{}} req.Header.Set("If-None-Match", etag) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.ServeHTTP(res, req) assert.Equal(t, http.StatusNotModified, res.Code) @@ -116,7 +116,7 @@ func TestProxy_Get(t *testing.T) { res = httptest.NewRecorder() req = &http.Request{Method: http.MethodGet, Header: map[string][]string{}} req.Header.Set("If-None-Match", etag) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.ServeHTTP(res, req) assert.Equal(t, http.StatusOK, res.Code) @@ -127,7 +127,7 @@ func TestProxy_Get(t *testing.T) { res = httptest.NewRecorder() req = &http.Request{Method: http.MethodGet, Header: map[string][]string{}} req.Header.Set("If-None-Match", etag) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.ServeHTTP(res, req) assert.Equal(t, http.StatusNotModified, res.Code) diff --git a/web/router.go b/web/router.go index 534d1bd..e9cbd46 100644 --- a/web/router.go +++ b/web/router.go @@ -63,7 +63,7 @@ func (s *HttpRouter) Close() { func (s *HttpRouter) setupSSERoutes(conf *config.SseConfig, sdkClients map[string]sdk.Client, l log.Logger) { s.sseServer = sse.NewServer(sdkClients, s.metrics, conf, l) - path := "/sse/:env/:data" + path := "/sse/:sdkId/:data" handler := mware.AutoOptions(s.sseServer.ServeHTTP) if len(conf.Headers) > 0 { handler = mware.ExtraHeaders(conf.Headers, handler) @@ -81,7 +81,7 @@ func (s *HttpRouter) setupSSERoutes(conf *config.SseConfig, sdkClients map[strin func (s *HttpRouter) setupWebhookRoutes(conf *config.WebhookConfig, sdkClients map[string]sdk.Client, l log.Logger) { s.webhookServer = webhook.NewServer(sdkClients, l) - path := "/hook/:env" + path := "/hook/:sdkId" handler := http.HandlerFunc(s.webhookServer.ServeHTTP) if conf.Auth.User != "" && conf.Auth.Password != "" { handler = mware.BasicAuth(conf.Auth.User, conf.Auth.Password, l, handler) @@ -102,7 +102,7 @@ func (s *HttpRouter) setupWebhookRoutes(conf *config.WebhookConfig, sdkClients m func (s *HttpRouter) setupCDNProxyRoutes(conf *config.CdnProxyConfig, sdkClients map[string]sdk.Client, l log.Logger) { s.cdnProxyServer = cdnproxy.NewServer(sdkClients, conf, l) - path := "/configuration-files/:env/:file" + path := "/configuration-files/:sdkId/:file" handler := mware.AutoOptions(mware.GZip(s.cdnProxyServer.ServeHTTP)) if len(conf.Headers) > 0 { handler = mware.ExtraHeaders(conf.Headers, handler) @@ -140,10 +140,11 @@ type endpoint struct { func (s *HttpRouter) setupAPIRoutes(conf *config.ApiConfig, sdkClients map[string]sdk.Client, l log.Logger) { s.apiServer = api.NewServer(sdkClients, conf, l) endpoints := []endpoint{ - {path: "/api/:env/eval", handler: mware.GZip(s.apiServer.Eval), method: http.MethodPost}, - {path: "/api/:env/eval-all", handler: mware.GZip(s.apiServer.EvalAll), method: http.MethodPost}, - {path: "/api/:env/keys", handler: mware.GZip(s.apiServer.Keys), method: http.MethodGet}, - {path: "/api/:env/refresh", handler: http.HandlerFunc(s.apiServer.Refresh), method: http.MethodPost}, + {path: "/api/:sdkId/eval", handler: mware.GZip(s.apiServer.Eval), method: http.MethodPost}, + {path: "/api/:sdkId/eval-all", handler: mware.GZip(s.apiServer.EvalAll), method: http.MethodPost}, + {path: "/api/:sdkId/keys", handler: mware.GZip(s.apiServer.Keys), method: http.MethodGet}, + {path: "/api/:sdkId/refresh", handler: http.HandlerFunc(s.apiServer.Refresh), method: http.MethodPost}, + {path: "/api/:sdkId/icanhascoffee", handler: http.HandlerFunc(s.apiServer.ICanHasCoffee), method: http.MethodGet}, } for _, endpoint := range endpoints { if len(conf.AuthHeaders) > 0 { @@ -165,5 +166,5 @@ func (s *HttpRouter) setupAPIRoutes(conf *config.ApiConfig, sdkClients map[strin s.router.HandlerFunc(endpoint.method, endpoint.path, endpoint.handler) s.router.HandlerFunc(http.MethodOptions, endpoint.path, endpoint.handler) } - l.Reportf("API enabled, accepting requests on path: /api/:env/*") + l.Reportf("API enabled, accepting requests on path: /api/:sdk/*") } diff --git a/web/router_status_test.go b/web/router_status_test.go index aa06b18..f26f88c 100644 --- a/web/router_status_test.go +++ b/web/router_status_test.go @@ -87,7 +87,7 @@ func newStatusRouter(t *testing.T) *HttpRouter { srv := httptest.NewServer(&h) opts := config.SDKConfig{BaseUrl: srv.URL, Key: key} ctx := testutils.NewTestSdkContext(&opts, nil) - conf := config.Config{Environments: map[string]*config.SDKConfig{"test": &opts}} + conf := config.Config{SDKs: map[string]*config.SDKConfig{"test": &opts}} reporter := status.NewReporter(&conf) ctx.StatusReporter = reporter client := sdk.NewClient(ctx, log.NewNullLogger()) diff --git a/web/sse/sse.go b/web/sse/sse.go index 1bc19e5..b1d2584 100644 --- a/web/sse/sse.go +++ b/web/sse/sse.go @@ -50,9 +50,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { http.Error(w, "'"+streamDataName+"' path parameter must be set", http.StatusBadRequest) return } - env := vars.ByName("env") - if env == "" { - http.Error(w, "'env' path parameter must be set", http.StatusBadRequest) + sdkId := vars.ByName("sdkId") + if sdkId == "" { + http.Error(w, "'sdkId' path parameter must be set", http.StatusBadRequest) return } streamContext, err := utils.Base64URLDecode(streamData) @@ -71,9 +71,9 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - str := s.streamServer.GetStreamOrNil(env) + str := s.streamServer.GetStreamOrNil(sdkId) if str == nil { - http.Error(w, "Invalid environment identifier: '"+env+"'", http.StatusBadRequest) + http.Error(w, "Invalid SDK identifier: '"+sdkId+"'", http.StatusBadRequest) } conn := str.CreateConnection(evalReq.Key, evalReq.User) diff --git a/web/sse/sse_test.go b/web/sse/sse_test.go index cd9fa8a..185697a 100644 --- a/web/sse/sse_test.go +++ b/web/sse/sse_test.go @@ -27,7 +27,7 @@ func TestSSE_Get(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) defer cancel() data := base64.URLEncoding.EncodeToString([]byte(`{"key":"flag"}`)) - params := httprouter.Params{httprouter.Param{Key: streamDataName, Value: data}, httprouter.Param{Key: "env", Value: "test"}} + params := httprouter.Params{httprouter.Param{Key: streamDataName, Value: data}, httprouter.Param{Key: "sdkId", Value: "test"}} ctx = context.WithValue(ctx, httprouter.ParamsKey, params) req = req.WithContext(ctx) srv.ServeHTTP(res, req) @@ -60,7 +60,7 @@ func TestSSE_Get_User(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) defer cancel() data := base64.URLEncoding.EncodeToString([]byte(`{"key":"flag","user":{"Identifier":"test"}}`)) - params := httprouter.Params{httprouter.Param{Key: streamDataName, Value: data}, httprouter.Param{Key: "env", Value: "test"}} + params := httprouter.Params{httprouter.Param{Key: streamDataName, Value: data}, httprouter.Param{Key: "sdkId", Value: "test"}} ctx = context.WithValue(ctx, httprouter.ParamsKey, params) req = req.WithContext(ctx) srv.ServeHTTP(res, req) diff --git a/web/webhook/webhook.go b/web/webhook/webhook.go index e5950dd..c4a1521 100644 --- a/web/webhook/webhook.go +++ b/web/webhook/webhook.go @@ -33,14 +33,14 @@ func NewServer(sdkClients map[string]sdk.Client, log log.Logger) *Server { func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { vars := httprouter.ParamsFromContext(r.Context()) - env := vars.ByName("env") - if env == "" { - http.Error(w, "'env' path parameter must be set", http.StatusBadRequest) + sdkId := vars.ByName("sdkId") + if sdkId == "" { + http.Error(w, "'sdkId' path parameter must be set", http.StatusBadRequest) return } - sdkClient, ok := s.sdkClients[env] + sdkClient, ok := s.sdkClients[sdkId] if !ok { - http.Error(w, "Invalid environment identifier: '"+env+"'", http.StatusBadRequest) + http.Error(w, "Invalid SDK identifier: '"+sdkId+"'", http.StatusBadRequest) return } diff --git a/web/webhook/webhook_test.go b/web/webhook/webhook_test.go index 0c92650..3ed55d9 100644 --- a/web/webhook/webhook_test.go +++ b/web/webhook/webhook_test.go @@ -30,7 +30,7 @@ func TestWebhook_Signature_Bad(t *testing.T) { t.Run("headers missing", func(t *testing.T) { res := httptest.NewRecorder() req := http.Request{Method: http.MethodGet} - utils.AddEnvContextParam(&req) + utils.AddSdkIdContextParam(&req) srv.ServeHTTP(res, &req) assert.Equal(t, http.StatusBadRequest, res.Code) }) @@ -40,7 +40,7 @@ func TestWebhook_Signature_Bad(t *testing.T) { req.Header.Set("X-ConfigCat-Webhook-Signature-V1", "wrong") req.Header.Set("X-ConfigCat-Webhook-ID", "1") req.Header.Set("X-ConfigCat-Webhook-Timestamp", strconv.FormatInt(time.Now().Unix(), 10)) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.ServeHTTP(res, req) assert.Equal(t, http.StatusBadRequest, res.Code) }) @@ -50,7 +50,7 @@ func TestWebhook_Signature_Bad(t *testing.T) { req.Header.Set("X-ConfigCat-Webhook-Signature-V1", "wrong") req.Header.Set("X-ConfigCat-Webhook-ID", "1") req.Header.Set("X-ConfigCat-Webhook-Timestamp", strconv.FormatInt(time.Now().Unix(), 10)) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) srv.ServeHTTP(res, req) assert.Equal(t, http.StatusBadRequest, res.Code) }) @@ -75,7 +75,7 @@ func TestWebhook_Signature_Ok(t *testing.T) { req.Header.Set("X-ConfigCat-Webhook-Signature-V1", signature) req.Header.Set("X-ConfigCat-Webhook-ID", id) req.Header.Set("X-ConfigCat-Webhook-Timestamp", timestamp) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) sub := clients["test"].SubConfigChanged("hook1") utils.WithTimeout(2*time.Second, func() { <-clients["test"].Ready() @@ -106,7 +106,7 @@ func TestWebhook_Signature_Ok(t *testing.T) { req.Header.Set("X-ConfigCat-Webhook-Signature-V1", signature) req.Header.Set("X-ConfigCat-Webhook-ID", id) req.Header.Set("X-ConfigCat-Webhook-Timestamp", timestamp) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) sub := clients["test"].SubConfigChanged("hook1") utils.WithTimeout(2*time.Second, func() { <-clients["test"].Ready() @@ -139,7 +139,7 @@ func TestWebhook_Signature_Replay_Reject(t *testing.T) { req.Header.Set("X-ConfigCat-Webhook-Signature-V1", signature) req.Header.Set("X-ConfigCat-Webhook-ID", id) req.Header.Set("X-ConfigCat-Webhook-Timestamp", timestamp) - utils.AddEnvContextParam(req) + utils.AddSdkIdContextParam(req) time.Sleep(2100 * time.Millisecond) // expire timestamp srv.ServeHTTP(res, req) assert.Equal(t, http.StatusBadRequest, res.Code)