From 821e686fd5235a3050377e818449e722706de7b5 Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Wed, 8 Nov 2023 15:45:40 -0300 Subject: [PATCH 01/19] WIP:add treatmentByFlagSet --- go.mod | 5 ++-- go.sum | 10 +++++--- splitio/client/client.go | 53 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 58 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 499d039..2947926 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/splitio/go-client/v6 go 1.18 require ( - github.com/splitio/go-split-commons/v5 v5.0.0 - github.com/splitio/go-toolkit/v5 v5.3.1 + github.com/splitio/go-split-commons/v5 v5.0.1-0.20231107180451-bc39808d0f93 + github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc ) require ( @@ -13,6 +13,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/redis/go-redis/v9 v9.0.4 // indirect + golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/sync v0.3.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 917f006..1fbd5e8 100644 --- a/go.sum +++ b/go.sum @@ -10,12 +10,14 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/redis/go-redis/v9 v9.0.4 h1:FC82T+CHJ/Q/PdyLW++GeCO+Ol59Y4T7R4jbgjvktgc= github.com/redis/go-redis/v9 v9.0.4/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= -github.com/splitio/go-split-commons/v5 v5.0.0 h1:bGRi0cf1JP5VNSi0a4BPQEWv/DACkeSKliazhPMVDPk= -github.com/splitio/go-split-commons/v5 v5.0.0/go.mod h1:lzoVmYJaCqB8UPSxWva0BZe7fF+bRJD+eP0rNi/lL7c= -github.com/splitio/go-toolkit/v5 v5.3.1 h1:9J/byd0fRxWj5/Zg0QZOnUxKBDIAMCGr7rySYzJKdJg= -github.com/splitio/go-toolkit/v5 v5.3.1/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231107180451-bc39808d0f93 h1:E/91apLmtONP5lVTBJJbBZUk/RNn7C2J7Z/8Q2yQo6s= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231107180451-bc39808d0f93/go.mod h1:PSkBLDXQW7NAhZ7JO1va7QJyTeDvpE7MEDnTdn5evRM= +github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc h1:14jdJE/rBEYfs1CO8kOQrj/8azszRFU4yw5FQIGpoJg= +github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/splitio/client/client.go b/splitio/client/client.go index 813c790..33c5b67 100644 --- a/splitio/client/client.go +++ b/splitio/client/client.go @@ -2,6 +2,7 @@ package client import ( "errors" + "fmt" "runtime/debug" "time" @@ -11,6 +12,7 @@ import ( "github.com/splitio/go-split-commons/v5/dtos" "github.com/splitio/go-split-commons/v5/engine/evaluator" "github.com/splitio/go-split-commons/v5/engine/evaluator/impressionlabels" + "github.com/splitio/go-split-commons/v5/flagsets" "github.com/splitio/go-split-commons/v5/provisional" "github.com/splitio/go-split-commons/v5/storage" "github.com/splitio/go-split-commons/v5/telemetry" @@ -18,10 +20,14 @@ import ( ) const ( - treatment = "Treatment" - treatments = "Treatments" - treatmentWithConfig = "TreatmentWithConfig" - treatmentsWithConfig = "TreatmentsWithConfig" + treatment = "Treatment" + treatments = "Treatments" + treatmentsByFlagSet = "TreatmentsByFlagSet" + treatmentsByFlagSets = "TreatmentsByFlahSets" + treatmentWithConfig = "TreatmentWithConfig" + treatmentsWithConfig = "TreatmentsWithConfig" + treatmentsWithConfigByFlagSet = "TreatmentWithConfigByFlagSet" + treatmentsWithConfigByFlagSets = "TrearmenteWithConfigByFlagSets" ) // SplitClient is the entry-point of the split SDK. @@ -37,6 +43,7 @@ type SplitClient struct { initTelemetry storage.TelemetryConfigProducer evaluationTelemetry storage.TelemetryEvaluationProducer runtimeTelemetry storage.TelemetryRuntimeProducer + flagSetsFilter flagsets.FlagSetFilter } // TreatmentResult struct that includes the Treatment evaluation with the corresponding Config @@ -274,6 +281,44 @@ func (c *SplitClient) Treatments(key interface{}, featureFlagNames []string, att return treatmentsResult } +func (c *SplitClient) TreatmentsByFlagSet(key interface{}, set string, attributes map[string]interface{}) map[string]string { + return c.TreatmentsByFlagSets(key, []string{set}, attributes) +} + +func (c *SplitClient) TreatmentsByFlagSets(key interface{}, sets []string, attributes map[string]interface{}) map[string]string { + treatmentsResult := map[string]string{} + if len(sets) == 0 { + c.logger.Warning("sets must be a non-empty array") + return treatmentsResult + } + sets, err := flagsets.SanitizeMany(sets) + if err != nil { + return treatmentsResult + } + sets = c.filterSetsAreInConfig(sets) + if len(sets) == 0 { + return treatmentsResult + } + if !c.isReady() + // result := c.doTreatmentsCall(key, featureFlagNames, attributes, treatments, telemetry.Treatments) + // for feature, treatmentResult := range result { + // treatmentsResult[feature] = treatmentResult.Treatment + // } + return treatmentsResult +} + +func (c *SplitClient) filterSetsAreInConfig(sets []string) []string { + toReturn := []string{} + for _, flagSet := range sets { + if !c.flagSetsFilter.IsPresent(flagSet) { + c.logger.Warning(fmt.Sprintf("you passed %s which is not part of the configured FlagSetsFilter, ignoring Flag Set.", flagSet)) + continue + } + toReturn = append(toReturn, flagSet) + } + return toReturn +} + // TreatmentsWithConfig evaluates multiple feature flag names for a single user and set of attributes at once and returns configurations func (c *SplitClient) TreatmentsWithConfig(key interface{}, featureFlagNames []string, attributes map[string]interface{}) map[string]TreatmentResult { return c.doTreatmentsCall(key, featureFlagNames, attributes, treatmentsWithConfig, telemetry.TreatmentsWithConfig) From 6556fccefadd343581b296e116d005d0a0cd42a7 Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Tue, 14 Nov 2023 13:55:30 -0300 Subject: [PATCH 02/19] [SDKS-7679] Implement getTreatments and create FlagSetsFilter in factory --- go.mod | 2 +- go.sum | 4 +- splitio/client/client.go | 132 +++++++++++++++---- splitio/client/client_test.go | 175 +++++++++++++++++++++++++ splitio/client/factory.go | 33 ++++- splitio/client/input_validator_test.go | 7 +- splitio/client/manager_test.go | 7 +- splitio/conf/sdkconf.go | 1 + splitio/conf/util.go | 7 +- 9 files changed, 327 insertions(+), 41 deletions(-) diff --git a/go.mod b/go.mod index 2947926..f32db2d 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/splitio/go-client/v6 go 1.18 require ( - github.com/splitio/go-split-commons/v5 v5.0.1-0.20231107180451-bc39808d0f93 + github.com/splitio/go-split-commons/v5 v5.0.1-0.20231114140907-c89079357dca github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc ) diff --git a/go.sum b/go.sum index 1fbd5e8..c24f40e 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/redis/go-redis/v9 v9.0.4 h1:FC82T+CHJ/Q/PdyLW++GeCO+Ol59Y4T7R4jbgjvktgc= github.com/redis/go-redis/v9 v9.0.4/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= -github.com/splitio/go-split-commons/v5 v5.0.1-0.20231107180451-bc39808d0f93 h1:E/91apLmtONP5lVTBJJbBZUk/RNn7C2J7Z/8Q2yQo6s= -github.com/splitio/go-split-commons/v5 v5.0.1-0.20231107180451-bc39808d0f93/go.mod h1:PSkBLDXQW7NAhZ7JO1va7QJyTeDvpE7MEDnTdn5evRM= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231114140907-c89079357dca h1:fWhN3KBkAO4FUFcvVX87MdShbiynf6IlgddAunuZul4= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231114140907-c89079357dca/go.mod h1:PSkBLDXQW7NAhZ7JO1va7QJyTeDvpE7MEDnTdn5evRM= github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc h1:14jdJE/rBEYfs1CO8kOQrj/8azszRFU4yw5FQIGpoJg= github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= diff --git a/splitio/client/client.go b/splitio/client/client.go index 33c5b67..664ac14 100644 --- a/splitio/client/client.go +++ b/splitio/client/client.go @@ -214,6 +214,28 @@ func (c *SplitClient) generateControlTreatments(featureFlagNames []string, opera return treatments } +func (c *SplitClient) processResult(result evaluator.Results, operation string, bucketingKey *string, matchingKey string, attributes map[string]interface{}, metricsLabel string) (t map[string]TreatmentResult) { + var bulkImpressions []dtos.Impression + treatments := make(map[string]TreatmentResult) + for feature, evaluation := range result.Evaluations { + if !c.validator.IsSplitFound(evaluation.Label, feature, operation) { + treatments[feature] = TreatmentResult{ + Treatment: evaluator.Control, + Config: nil, + } + } else { + bulkImpressions = append(bulkImpressions, c.createImpression(feature, bucketingKey, evaluation.Label, matchingKey, evaluation.Treatment, evaluation.SplitChangeNumber)) + + treatments[feature] = TreatmentResult{ + Treatment: evaluation.Treatment, + Config: evaluation.Config, + } + } + } + c.storeData(bulkImpressions, attributes, metricsLabel, result.EvaluationTime) + return treatments +} + // doTreatmentsCall retrieves treatments of an specific array of feature flag names with configurations object if it is present for a certain key and set of attributes func (c *SplitClient) doTreatmentsCall(key interface{}, featureFlagNames []string, attributes map[string]interface{}, operation string, metricsLabel string) (t map[string]TreatmentResult) { treatments := make(map[string]TreatmentResult) @@ -248,26 +270,44 @@ func (c *SplitClient) doTreatmentsCall(key interface{}, featureFlagNames []strin return map[string]TreatmentResult{} } - var bulkImpressions []dtos.Impression evaluationsResult := c.getEvaluationsResult(matchingKey, bucketingKey, filteredFeatures, attributes, operation) - for feature, evaluation := range evaluationsResult.Evaluations { - if !c.validator.IsSplitFound(evaluation.Label, feature, operation) { - treatments[feature] = TreatmentResult{ - Treatment: evaluator.Control, - Config: nil, - } - } else { - bulkImpressions = append(bulkImpressions, c.createImpression(feature, bucketingKey, evaluation.Label, matchingKey, evaluation.Treatment, evaluation.SplitChangeNumber)) - treatments[feature] = TreatmentResult{ - Treatment: evaluation.Treatment, - Config: evaluation.Config, - } + treatments = c.processResult(evaluationsResult, operation, bucketingKey, matchingKey, attributes, metricsLabel) + + return treatments +} + +// doTreatmentsCallByFlagSets retrieves treatments of a specific array of feature flag names, that belong to flag sets, with configurations object if it is present for a certain key and set of attributes +func (c *SplitClient) doTreatmentsCallByFlagSets(key interface{}, sets []string, attributes map[string]interface{}, operation string, metricsLabel string) (t map[string]TreatmentResult) { + treatments := make(map[string]TreatmentResult) + + // Set up a guard deferred function to recover if the SDK starts panicking + defer func() { + if r := recover(); r != nil { + // At this point we'll only trust that the logger isn't panicking trust + // that the logger isn't panicking + c.evaluationTelemetry.RecordException(metricsLabel) + c.logger.Error( + "SDK is panicking with the following error", r, "\n", + string(debug.Stack()), "\n") + t = treatments } + }() + + if c.isDestroyed() { + return treatments } - c.storeData(bulkImpressions, attributes, metricsLabel, evaluationsResult.EvaluationTime) + matchingKey, bucketingKey, err := c.validator.ValidateTreatmentKey(key, operation) + if err != nil { + c.logger.Error(err.Error()) + return treatments + } + if c.isReady() { + evaluationsResult := c.evaluator.EvaluateFeatureByFlagSets(matchingKey, bucketingKey, sets, attributes) + treatments = c.processResult(evaluationsResult, operation, bucketingKey, matchingKey, attributes, metricsLabel) + } return treatments } @@ -281,29 +321,47 @@ func (c *SplitClient) Treatments(key interface{}, featureFlagNames []string, att return treatmentsResult } -func (c *SplitClient) TreatmentsByFlagSet(key interface{}, set string, attributes map[string]interface{}) map[string]string { - return c.TreatmentsByFlagSets(key, []string{set}, attributes) -} - -func (c *SplitClient) TreatmentsByFlagSets(key interface{}, sets []string, attributes map[string]interface{}) map[string]string { - treatmentsResult := map[string]string{} +func (c *SplitClient) validateSets(sets []string) []string { if len(sets) == 0 { c.logger.Warning("sets must be a non-empty array") - return treatmentsResult + return nil } sets, err := flagsets.SanitizeMany(sets) if err != nil { - return treatmentsResult + return nil } sets = c.filterSetsAreInConfig(sets) if len(sets) == 0 { + return nil + } + return sets +} + +// Treatments evaluate multiple feature flag names belonging to a flag set for a single user and a set of attributes at once +func (c *SplitClient) TreatmentsByFlagSet(key interface{}, set string, attributes map[string]interface{}) map[string]string { + treatmentsResult := map[string]string{} + sets := c.validateSets([]string{set}) + if sets == nil { + return treatmentsResult + } + result := c.doTreatmentsCallByFlagSets(key, sets, attributes, treatmentsByFlagSet, telemetry.TreatmentsByFlagSet) + for feature, treatmentResult := range result { + treatmentsResult[feature] = treatmentResult.Treatment + } + return treatmentsResult +} + +// Treatments evaluate multiple feature flag names belonging to flag sets for a single user and a set of attributes at once +func (c *SplitClient) TreatmentsByFlagSets(key interface{}, sets []string, attributes map[string]interface{}) map[string]string { + treatmentsResult := map[string]string{} + sets = c.validateSets(sets) + if sets == nil { return treatmentsResult } - if !c.isReady() - // result := c.doTreatmentsCall(key, featureFlagNames, attributes, treatments, telemetry.Treatments) - // for feature, treatmentResult := range result { - // treatmentsResult[feature] = treatmentResult.Treatment - // } + result := c.doTreatmentsCallByFlagSets(key, sets, attributes, treatmentsByFlagSets, telemetry.TreatmentsByFlagSets) + for feature, treatmentResult := range result { + treatmentsResult[feature] = treatmentResult.Treatment + } return treatmentsResult } @@ -324,6 +382,26 @@ func (c *SplitClient) TreatmentsWithConfig(key interface{}, featureFlagNames []s return c.doTreatmentsCall(key, featureFlagNames, attributes, treatmentsWithConfig, telemetry.TreatmentsWithConfig) } +// TreatmentsWithConfigByFlagSet evaluates multiple feature flag names belonging to a flag set for a single user and set of attributes at once and returns configurations +func (c *SplitClient) TreatmentsWithConfigByFlagSet(key interface{}, set string, attributes map[string]interface{}) map[string]TreatmentResult { + treatmentsResult := make(map[string]TreatmentResult) + sets := c.validateSets([]string{set}) + if sets == nil { + return treatmentsResult + } + return c.doTreatmentsCallByFlagSets(key, sets, attributes, treatmentsWithConfigByFlagSet, telemetry.TreatmentsByFlagSets) +} + +// TreatmentsWithConfigByFlagSet evaluates multiple feature flag names belonging to a flag sets for a single user and set of attributes at once and returns configurations +func (c *SplitClient) TreatmentsWithConfigByFlagSets(key interface{}, sets []string, attributes map[string]interface{}) map[string]TreatmentResult { + treatmentsResult := make(map[string]TreatmentResult) + sets = c.validateSets(sets) + if sets == nil { + return treatmentsResult + } + return c.doTreatmentsCallByFlagSets(key, sets, attributes, treatmentsWithConfigByFlagSets, telemetry.TreatmentsByFlagSets) +} + // isDestroyed returns true if the client has been destroyed func (c *SplitClient) isDestroyed() bool { return c.factory.IsDestroyed() diff --git a/splitio/client/client_test.go b/splitio/client/client_test.go index e6bff95..46c9231 100644 --- a/splitio/client/client_test.go +++ b/splitio/client/client_test.go @@ -44,6 +44,11 @@ import ( type mockEvaluator struct{} +// EvaluateFeatureByFlagSets implements evaluator.Interface. +func (*mockEvaluator) EvaluateFeatureByFlagSets(key string, bucketingKey *string, flagSets []string, attributes map[string]interface{}) evaluator.Results { + panic("unimplemented") +} + func (e *mockEvaluator) EvaluateFeature( key string, bucketingKey *string, @@ -151,6 +156,32 @@ func getFactory() SplitFactory { } } +func getFactoryByFlagSets() SplitFactory { + telemetryStorage, _ := inmemory.NewTelemetryStorage() + cfg := conf.Default() + cfg.LabelsEnabled = true + cfg.Advanced.FlagSetFilter = []string{"set1", "set2"} + logger := logging.NewLogger(nil) + + impressionObserver, _ := strategy.NewImpressionObserver(500) + impressionsCounter := strategy.NewImpressionsCounter() + impressionsStrategy := strategy.NewOptimizedImpl(impressionObserver, impressionsCounter, telemetryStorage, false) + impressionManager := provisional.NewImpressionManager(impressionsStrategy) + + return SplitFactory{ + cfg: cfg, + storages: sdkStorages{ + impressions: mutexqueue.NewMQImpressionsStorage(cfg.Advanced.ImpressionsQueueSize, make(chan string, 1), logger, telemetryStorage), + events: mocks.MockEventStorage{}, + initTelemetry: telemetryStorage, + runtimeTelemetry: telemetryStorage, + evaluationTelemetry: telemetryStorage, + }, + impressionManager: impressionManager, + logger: logger, + } +} + func expectedTreatment(treatment string, expectedTreatment string, t *testing.T) { if treatment != expectedTreatment { t.Error("Expected: " + expectedTreatment + " actual: " + treatment) @@ -197,6 +228,150 @@ func TestClientGetTreatment(t *testing.T) { } } +func TestClientGetTreatmentByFlagSet(t *testing.T) { + factory := getFactoryByFlagSets() + client := factory.Client() + client.evaluator = evaluatorMock.MockEvaluator{ + EvaluateFeatureByFlagSetsCall: func(key string, bucketingKey *string, flagSets []string, attributes map[string]interface{}) evaluator.Results { + results := evaluator.Results{ + Evaluations: make(map[string]evaluator.Result), + EvaluationTime: 0, + } + for _, flagSet := range flagSets { + switch flagSet { + case "set1": + results.Evaluations["feature"] = evaluator.Result{ + EvaluationTime: 0, + Label: "aLabel", + SplitChangeNumber: 123, + Treatment: "TreatmentA", + } + default: + t.Error("Should be set1 or set2") + } + } + return results + }, + } + factory.status.Store(sdkStatusReady) + + res := client.TreatmentsByFlagSet("user1", "set1", nil) + + expectedTreatment(res["feature"], "TreatmentA", t) +} + +func TestClientGetTreatmentByFlagSets(t *testing.T) { + factory := getFactory() + client := factory.Client() + client.evaluator = evaluatorMock.MockEvaluator{ + EvaluateFeatureByFlagSetsCall: func(key string, bucketingKey *string, flagSets []string, attributes map[string]interface{}) evaluator.Results { + results := evaluator.Results{ + Evaluations: make(map[string]evaluator.Result), + EvaluationTime: 0, + } + for _, flagSet := range flagSets { + switch flagSet { + case "set1": + results.Evaluations["feature"] = evaluator.Result{ + EvaluationTime: 0, + Label: "aLabel", + SplitChangeNumber: 123, + Treatment: "TreatmentA", + } + case "set2": + results.Evaluations["feature2"] = evaluator.Result{ + EvaluationTime: 0, + Label: "bLabel", + SplitChangeNumber: 123, + Treatment: "TreatmentB", + } + default: + t.Error("Should be set1 or set2") + } + } + return results + }, + } + factory.status.Store(sdkStatusReady) + + res := client.TreatmentsByFlagSets("user1", []string{"set1", "set2"}, nil) + + expectedTreatment(res["feature"], "TreatmentA", t) + expectedTreatment(res["feature2"], "TreatmentB", t) +} + +func TestClientGetTreatmentWithConfigByFlagSet(t *testing.T) { + factory := getFactory() + client := factory.Client() + client.evaluator = evaluatorMock.MockEvaluator{ + EvaluateFeatureByFlagSetsCall: func(key string, bucketingKey *string, flagSets []string, attributes map[string]interface{}) evaluator.Results { + results := evaluator.Results{ + Evaluations: make(map[string]evaluator.Result), + EvaluationTime: 0, + } + for _, flagSet := range flagSets { + switch flagSet { + case "set1": + results.Evaluations["feature"] = evaluator.Result{ + EvaluationTime: 0, + Label: "aLabel", + SplitChangeNumber: 123, + Treatment: "TreatmentA", + } + default: + t.Error("Should be set1 or set2") + } + } + return results + }, + } + factory.status.Store(sdkStatusReady) + + res := client.TreatmentsWithConfigByFlagSet("user1", "set1", nil) + + expectedTreatment(res["feature"].Treatment, "TreatmentA", t) +} + +func TestClientGetTreatmentWithConfigByFlagSets(t *testing.T) { + factory := getFactory() + client := factory.Client() + client.evaluator = evaluatorMock.MockEvaluator{ + EvaluateFeatureByFlagSetsCall: func(key string, bucketingKey *string, flagSets []string, attributes map[string]interface{}) evaluator.Results { + results := evaluator.Results{ + Evaluations: make(map[string]evaluator.Result), + EvaluationTime: 0, + } + for _, flagSet := range flagSets { + switch flagSet { + case "set1": + results.Evaluations["feature"] = evaluator.Result{ + EvaluationTime: 0, + Label: "aLabel", + SplitChangeNumber: 123, + Treatment: "TreatmentA", + } + case "set2": + results.Evaluations["feature2"] = evaluator.Result{ + EvaluationTime: 0, + Label: "bLabel", + SplitChangeNumber: 123, + Treatment: "TreatmentB", + } + default: + t.Error("Should be set1 or set2") + } + } + return results + }, + } + factory.status.Store(sdkStatusReady) + + res := client.TreatmentsWithConfigByFlagSets("user1", []string{"set1", "set2"}, nil) + + expectedTreatment(res["feature"].Treatment, "TreatmentA", t) + expectedTreatment(res["feature2"].Treatment, "TreatmentB", t) +} + func TestTreatments(t *testing.T) { factory := getFactory() client := factory.Client() diff --git a/splitio/client/factory.go b/splitio/client/factory.go index aca1750..38fde22 100644 --- a/splitio/client/factory.go +++ b/splitio/client/factory.go @@ -18,6 +18,7 @@ import ( "github.com/splitio/go-split-commons/v5/dtos" "github.com/splitio/go-split-commons/v5/engine" "github.com/splitio/go-split-commons/v5/engine/evaluator" + "github.com/splitio/go-split-commons/v5/flagsets" "github.com/splitio/go-split-commons/v5/healthcheck/application" "github.com/splitio/go-split-commons/v5/provisional" "github.com/splitio/go-split-commons/v5/provisional/strategy" @@ -283,13 +284,16 @@ func setupInMemoryFactory( logger logging.LoggerInterface, metadata dtos.Metadata, ) (*SplitFactory, error) { - advanced := conf.NormalizeSDKConf(cfg.Advanced) + advanced, errs := conf.NormalizeSDKConf(cfg.Advanced) + printWarnings(logger, errs) if strings.TrimSpace(cfg.SplitSyncProxyURL) != "" { advanced.StreamingEnabled = false } inMememoryFullQueue := make(chan string, 2) // Size 2: So that it's able to accept one event from each resource simultaneously. - splitsStorage := mutexmap.NewMMSplitStorage() + + flagSetFilter := flagsets.NewFlagSetFilter(advanced.FlagSetsFilter) + splitsStorage := mutexmap.NewMMSplitStorage(flagSetFilter) segmentsStorage := mutexmap.NewMMSegmentStorage() telemetryStorage, err := inmemory.NewTelemetryStorage() impressionsStorage := mutexqueue.NewMQImpressionsStorage(cfg.Advanced.ImpressionsQueueSize, inMememoryFullQueue, logger, telemetryStorage) @@ -302,7 +306,7 @@ func setupInMemoryFactory( splitAPI := api.NewSplitAPI(apikey, advanced, logger, metadata) workers := synchronizer.Workers{ - SplitUpdater: split.NewSplitUpdater(splitsStorage, splitAPI.SplitFetcher, logger, telemetryStorage, dummyHC), + SplitUpdater: split.NewSplitUpdater(splitsStorage, splitAPI.SplitFetcher, logger, telemetryStorage, dummyHC, flagSetFilter), SegmentUpdater: segment.NewSegmentUpdater(splitsStorage, segmentsStorage, splitAPI.SegmentFetcher, logger, telemetryStorage, dummyHC), EventRecorder: event.NewEventRecorderSingle(eventsStorage, splitAPI.EventRecorder, logger, metadata, telemetryStorage), TelemetryRecorder: telemetry.NewTelemetrySynchronizer(telemetryStorage, splitAPI.TelemetryRecorder, splitsStorage, segmentsStorage, logger, metadata, telemetryStorage), @@ -396,8 +400,13 @@ func setupRedisFactory(apikey string, cfg *conf.SplitSdkConfig, logger logging.L } inMememoryFullQueue := make(chan string, 2) // Size 2: So that it's able to accept one event from each resource simultaneously. impressionStorage := redis.NewImpressionStorage(redisClient, metadata, logger) + + flagSets, errs := flagsets.SanitizeMany(cfg.Advanced.FlagSetFilter) + printWarnings(logger, errs) + flagSetFilter := flagsets.NewFlagSetFilter(flagSets) + storages := sdkStorages{ - splits: redis.NewSplitStorage(redisClient, logger), + splits: redis.NewSplitStorage(redisClient, logger, flagSetFilter), segments: redis.NewSegmentStorage(redisClient, logger), impressionsConsumer: impressionStorage, impressions: impressionStorage, @@ -458,7 +467,10 @@ func setupLocalhostFactory( logger logging.LoggerInterface, metadata dtos.Metadata, ) (*SplitFactory, error) { - splitStorage := mutexmap.NewMMSplitStorage() + flagSets, errs := flagsets.SanitizeMany(cfg.Advanced.FlagSetFilter) + printWarnings(logger, errs) + flagSetFilter := flagsets.NewFlagSetFilter(flagSets) + splitStorage := mutexmap.NewMMSplitStorage(flagSetFilter) segmentStorage := mutexmap.NewMMSegmentStorage() telemetryStorage, err := inmemory.NewTelemetryStorage() if err != nil { @@ -640,3 +652,14 @@ func buildImpressionManager( return provisional.NewImpressionManager(impressionsStrategy), nil } } + +func printWarnings(logger logging.LoggerInterface, errs []error) { + if len(errs) != 0 { + for _, err := range errs { + if errType, ok := err.(*dtos.FlagSetValidatonError); ok { + logger.Warning(errType.Message) + } + } + errs = nil + } +} diff --git a/splitio/client/input_validator_test.go b/splitio/client/input_validator_test.go index 4f41539..73e401a 100644 --- a/splitio/client/input_validator_test.go +++ b/splitio/client/input_validator_test.go @@ -12,6 +12,7 @@ import ( "github.com/splitio/go-client/v6/splitio/conf" spConf "github.com/splitio/go-split-commons/v5/conf" "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/flagsets" "github.com/splitio/go-split-commons/v5/healthcheck/application" "github.com/splitio/go-split-commons/v5/provisional" "github.com/splitio/go-split-commons/v5/provisional/strategy" @@ -542,11 +543,12 @@ func TestNotReadyYet(t *testing.T) { initTelemetry: telemetryStorage, evaluationTelemetry: telemetryStorage, } + flagSetFilter := flagsets.NewFlagSetFilter([]string{}) maganerNotReady := SplitManager{ initTelemetry: telemetryStorage, factory: factoryNotReady, logger: logger, - splitStorage: mutexmap.NewMMSplitStorage(), + splitStorage: mutexmap.NewMMSplitStorage(flagSetFilter), } factoryNotReady.status.Store(sdkStatusInitializing) @@ -597,7 +599,8 @@ func TestNotReadyYet(t *testing.T) { } func TestManagerWithEmptySplit(t *testing.T) { - splitStorage := mutexmap.NewMMSplitStorage() + flagSetFilter := flagsets.NewFlagSetFilter([]string{}) + splitStorage := mutexmap.NewMMSplitStorage(flagSetFilter) factory := SplitFactory{} manager := SplitManager{ splitStorage: splitStorage, diff --git a/splitio/client/manager_test.go b/splitio/client/manager_test.go index d95df99..12d03ac 100644 --- a/splitio/client/manager_test.go +++ b/splitio/client/manager_test.go @@ -4,13 +4,15 @@ import ( "testing" "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/flagsets" "github.com/splitio/go-split-commons/v5/storage/inmemory/mutexmap" "github.com/splitio/go-toolkit/v5/datastructures/set" "github.com/splitio/go-toolkit/v5/logging" ) func TestSplitManager(t *testing.T) { - splitStorage := mutexmap.NewMMSplitStorage() + flagSetFilter := flagsets.NewFlagSetFilter([]string{}) + splitStorage := mutexmap.NewMMSplitStorage(flagSetFilter) splitStorage.Update([]dtos.SplitDTO{ { ChangeNumber: 123, @@ -89,7 +91,8 @@ func TestSplitManager(t *testing.T) { } func TestSplitManagerWithConfigs(t *testing.T) { - splitStorage := mutexmap.NewMMSplitStorage() + flagSetFilter := flagsets.NewFlagSetFilter([]string{}) + splitStorage := mutexmap.NewMMSplitStorage(flagSetFilter) splitStorage.Update([]dtos.SplitDTO{*valid, *killed, *noConfig}, nil, 123) logger := logging.NewLogger(nil) diff --git a/splitio/conf/sdkconf.go b/splitio/conf/sdkconf.go index e94cb76..1f3ab62 100644 --- a/splitio/conf/sdkconf.go +++ b/splitio/conf/sdkconf.go @@ -94,6 +94,7 @@ type AdvancedConfig struct { ImpressionsQueueSize int ImpressionsBulkSize int64 StreamingEnabled bool + FlagSetFilter []string } // Default returns a config struct with all the default values diff --git a/splitio/conf/util.go b/splitio/conf/util.go index 5e89f55..378d4e9 100644 --- a/splitio/conf/util.go +++ b/splitio/conf/util.go @@ -4,10 +4,11 @@ import ( "strings" "github.com/splitio/go-split-commons/v5/conf" + "github.com/splitio/go-split-commons/v5/flagsets" ) // NormalizeSDKConf compares against SDK Config to set defaults -func NormalizeSDKConf(sdkConfig AdvancedConfig) conf.AdvancedConfig { +func NormalizeSDKConf(sdkConfig AdvancedConfig) (conf.AdvancedConfig, []error) { config := conf.GetDefaultAdvancedConfig() if sdkConfig.HTTPTimeout > 0 { config.HTTPTimeout = sdkConfig.HTTPTimeout @@ -47,5 +48,7 @@ func NormalizeSDKConf(sdkConfig AdvancedConfig) conf.AdvancedConfig { } config.StreamingEnabled = sdkConfig.StreamingEnabled - return config + flagSets, errs := flagsets.SanitizeMany(sdkConfig.FlagSetFilter) + config.FlagSetsFilter = flagSets + return config, errs } From e65392af97c8e1c470866ae83a62da3a7f503d06 Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Tue, 14 Nov 2023 14:12:02 -0300 Subject: [PATCH 03/19] FlagSet warnings point to nil after print them --- splitio/client/factory.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/splitio/client/factory.go b/splitio/client/factory.go index 38fde22..773318e 100644 --- a/splitio/client/factory.go +++ b/splitio/client/factory.go @@ -285,7 +285,7 @@ func setupInMemoryFactory( metadata dtos.Metadata, ) (*SplitFactory, error) { advanced, errs := conf.NormalizeSDKConf(cfg.Advanced) - printWarnings(logger, errs) + printWarnings(logger, &errs) if strings.TrimSpace(cfg.SplitSyncProxyURL) != "" { advanced.StreamingEnabled = false } @@ -402,7 +402,7 @@ func setupRedisFactory(apikey string, cfg *conf.SplitSdkConfig, logger logging.L impressionStorage := redis.NewImpressionStorage(redisClient, metadata, logger) flagSets, errs := flagsets.SanitizeMany(cfg.Advanced.FlagSetFilter) - printWarnings(logger, errs) + printWarnings(logger, &errs) flagSetFilter := flagsets.NewFlagSetFilter(flagSets) storages := sdkStorages{ @@ -468,7 +468,7 @@ func setupLocalhostFactory( metadata dtos.Metadata, ) (*SplitFactory, error) { flagSets, errs := flagsets.SanitizeMany(cfg.Advanced.FlagSetFilter) - printWarnings(logger, errs) + printWarnings(logger, &errs) flagSetFilter := flagsets.NewFlagSetFilter(flagSets) splitStorage := mutexmap.NewMMSplitStorage(flagSetFilter) segmentStorage := mutexmap.NewMMSegmentStorage() @@ -653,13 +653,13 @@ func buildImpressionManager( } } -func printWarnings(logger logging.LoggerInterface, errs []error) { - if len(errs) != 0 { - for _, err := range errs { +func printWarnings(logger logging.LoggerInterface, errs *[]error) { + if len(*errs) != 0 { + for _, err := range *errs { if errType, ok := err.(*dtos.FlagSetValidatonError); ok { logger.Warning(errType.Message) } } - errs = nil } + errs = nil } From 024222f5f4db9358995bb28428d667010c3d4d03 Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Tue, 14 Nov 2023 14:49:35 -0300 Subject: [PATCH 04/19] Pr suggestions --- go.mod | 2 +- go.sum | 4 ++-- splitio/client/client.go | 14 +++++++++----- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index f32db2d..cd4331f 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/splitio/go-client/v6 go 1.18 require ( - github.com/splitio/go-split-commons/v5 v5.0.1-0.20231114140907-c89079357dca + github.com/splitio/go-split-commons/v5 v5.0.1-0.20231114174555-e7fa17527a05 github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc ) diff --git a/go.sum b/go.sum index c24f40e..907f417 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/redis/go-redis/v9 v9.0.4 h1:FC82T+CHJ/Q/PdyLW++GeCO+Ol59Y4T7R4jbgjvktgc= github.com/redis/go-redis/v9 v9.0.4/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= -github.com/splitio/go-split-commons/v5 v5.0.1-0.20231114140907-c89079357dca h1:fWhN3KBkAO4FUFcvVX87MdShbiynf6IlgddAunuZul4= -github.com/splitio/go-split-commons/v5 v5.0.1-0.20231114140907-c89079357dca/go.mod h1:PSkBLDXQW7NAhZ7JO1va7QJyTeDvpE7MEDnTdn5evRM= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231114174555-e7fa17527a05 h1:rDWd6xVhU/XCmWH28+8CnWkJOZ+8yoKxm2+rbX3HahI= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231114174555-e7fa17527a05/go.mod h1:PSkBLDXQW7NAhZ7JO1va7QJyTeDvpE7MEDnTdn5evRM= github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc h1:14jdJE/rBEYfs1CO8kOQrj/8azszRFU4yw5FQIGpoJg= github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= diff --git a/splitio/client/client.go b/splitio/client/client.go index 664ac14..7916f86 100644 --- a/splitio/client/client.go +++ b/splitio/client/client.go @@ -26,8 +26,8 @@ const ( treatmentsByFlagSets = "TreatmentsByFlahSets" treatmentWithConfig = "TreatmentWithConfig" treatmentsWithConfig = "TreatmentsWithConfig" - treatmentsWithConfigByFlagSet = "TreatmentWithConfigByFlagSet" - treatmentsWithConfigByFlagSets = "TrearmenteWithConfigByFlagSets" + treatmentsWithConfigByFlagSet = "TreatmentsWithConfigByFlagSet" + treatmentsWithConfigByFlagSets = "TrearmentsWithConfigByFlagSets" ) // SplitClient is the entry-point of the split SDK. @@ -326,9 +326,13 @@ func (c *SplitClient) validateSets(sets []string) []string { c.logger.Warning("sets must be a non-empty array") return nil } - sets, err := flagsets.SanitizeMany(sets) - if err != nil { - return nil + sets, errs := flagsets.SanitizeMany(sets) + if len(errs) != 0 { + for _, err := range errs { + if errType, ok := err.(*dtos.FlagSetValidatonError); ok { + c.logger.Warning(errType.Message) + } + } } sets = c.filterSetsAreInConfig(sets) if len(sets) == 0 { From b2cca4905909423b7f8e9e707e123996900feb37 Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Tue, 14 Nov 2023 17:58:43 -0300 Subject: [PATCH 05/19] Fix print flag sets warnings --- splitio/client/factory.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/splitio/client/factory.go b/splitio/client/factory.go index 773318e..7b70fd5 100644 --- a/splitio/client/factory.go +++ b/splitio/client/factory.go @@ -285,7 +285,7 @@ func setupInMemoryFactory( metadata dtos.Metadata, ) (*SplitFactory, error) { advanced, errs := conf.NormalizeSDKConf(cfg.Advanced) - printWarnings(logger, &errs) + printWarnings(logger, errs) if strings.TrimSpace(cfg.SplitSyncProxyURL) != "" { advanced.StreamingEnabled = false } @@ -402,7 +402,7 @@ func setupRedisFactory(apikey string, cfg *conf.SplitSdkConfig, logger logging.L impressionStorage := redis.NewImpressionStorage(redisClient, metadata, logger) flagSets, errs := flagsets.SanitizeMany(cfg.Advanced.FlagSetFilter) - printWarnings(logger, &errs) + printWarnings(logger, errs) flagSetFilter := flagsets.NewFlagSetFilter(flagSets) storages := sdkStorages{ @@ -468,7 +468,7 @@ func setupLocalhostFactory( metadata dtos.Metadata, ) (*SplitFactory, error) { flagSets, errs := flagsets.SanitizeMany(cfg.Advanced.FlagSetFilter) - printWarnings(logger, &errs) + printWarnings(logger, errs) flagSetFilter := flagsets.NewFlagSetFilter(flagSets) splitStorage := mutexmap.NewMMSplitStorage(flagSetFilter) segmentStorage := mutexmap.NewMMSegmentStorage() @@ -653,13 +653,12 @@ func buildImpressionManager( } } -func printWarnings(logger logging.LoggerInterface, errs *[]error) { - if len(*errs) != 0 { - for _, err := range *errs { +func printWarnings(logger logging.LoggerInterface, errs []error) { + if len(errs) != 0 { + for _, err := range errs { if errType, ok := err.(*dtos.FlagSetValidatonError); ok { logger.Warning(errType.Message) } } } - errs = nil } From ed04468894976a4244004f38131a4e6c8a791922 Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Wed, 15 Nov 2023 11:03:06 -0300 Subject: [PATCH 06/19] Add test case to validate flag set warnings --- splitio/client/factory.go | 6 +++--- splitio/client/factory_test.go | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 splitio/client/factory_test.go diff --git a/splitio/client/factory.go b/splitio/client/factory.go index 7b70fd5..48d35ed 100644 --- a/splitio/client/factory.go +++ b/splitio/client/factory.go @@ -284,8 +284,8 @@ func setupInMemoryFactory( logger logging.LoggerInterface, metadata dtos.Metadata, ) (*SplitFactory, error) { - advanced, errs := conf.NormalizeSDKConf(cfg.Advanced) - printWarnings(logger, errs) + advanced, warnings := conf.NormalizeSDKConf(cfg.Advanced) + printWarnings(logger, warnings) if strings.TrimSpace(cfg.SplitSyncProxyURL) != "" { advanced.StreamingEnabled = false } @@ -656,7 +656,7 @@ func buildImpressionManager( func printWarnings(logger logging.LoggerInterface, errs []error) { if len(errs) != 0 { for _, err := range errs { - if errType, ok := err.(*dtos.FlagSetValidatonError); ok { + if errType, ok := err.(dtos.FlagSetValidatonError); ok { logger.Warning(errType.Message) } } diff --git a/splitio/client/factory_test.go b/splitio/client/factory_test.go new file mode 100644 index 0000000..a751260 --- /dev/null +++ b/splitio/client/factory_test.go @@ -0,0 +1,35 @@ +package client + +import ( + "testing" + + "github.com/splitio/go-split-commons/v5/flagsets" +) + +func TestPrintWarnings(t *testing.T) { + + flagSets, warnings := flagsets.SanitizeMany([]string{"set1", " set2"}) + if len(flagSets) != 2 { + t.Error("flag set size should be 2") + } + printWarnings(getMockedLogger(), warnings) + if !mW.Matches("Flag Set name set2 has extra whitespace, trimming") { + t.Error("Wrong message") + } + flagSets, warnings = flagsets.SanitizeMany([]string{"set1", "Set2"}) + if len(flagSets) != 2 { + t.Error("flag set size should be 2") + } + printWarnings(getMockedLogger(), warnings) + if !mW.Matches("Flag Set name Set2 should be all lowercase - converting string to lowercase") { + t.Error("Wrong message") + } + flagSets, warnings = flagsets.SanitizeMany([]string{"set1", "@set4"}) + if len(flagSets) != 1 { + t.Error("flag set size should be 1") + } + printWarnings(getMockedLogger(), warnings) + if !mW.Matches("you passed @set4, Flag Set must adhere to the regular expressions ^[a-z0-9][_a-z0-9]{0,49}$. This means a Flag Set must start with a letter or number, be in lowercase, alphanumeric and have a max length of 50 characters. @set4 was discarded.") { + t.Error("Wrong message") + } +} From 52cd6c6ab23cf71d425f98f19625e5106846e8fd Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Wed, 15 Nov 2023 12:18:13 -0300 Subject: [PATCH 07/19] Pr suggestions --- splitio/client/client.go | 44 ++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/splitio/client/client.go b/splitio/client/client.go index 7916f86..e4dfd39 100644 --- a/splitio/client/client.go +++ b/splitio/client/client.go @@ -278,7 +278,7 @@ func (c *SplitClient) doTreatmentsCall(key interface{}, featureFlagNames []strin } // doTreatmentsCallByFlagSets retrieves treatments of a specific array of feature flag names, that belong to flag sets, with configurations object if it is present for a certain key and set of attributes -func (c *SplitClient) doTreatmentsCallByFlagSets(key interface{}, sets []string, attributes map[string]interface{}, operation string, metricsLabel string) (t map[string]TreatmentResult) { +func (c *SplitClient) doTreatmentsCallByFlagSets(key interface{}, flagSets []string, attributes map[string]interface{}, operation string, metricsLabel string) (t map[string]TreatmentResult) { treatments := make(map[string]TreatmentResult) // Set up a guard deferred function to recover if the SDK starts panicking @@ -305,7 +305,7 @@ func (c *SplitClient) doTreatmentsCallByFlagSets(key interface{}, sets []string, } if c.isReady() { - evaluationsResult := c.evaluator.EvaluateFeatureByFlagSets(matchingKey, bucketingKey, sets, attributes) + evaluationsResult := c.evaluator.EvaluateFeatureByFlagSets(matchingKey, bucketingKey, flagSets, attributes) treatments = c.processResult(evaluationsResult, operation, bucketingKey, matchingKey, attributes, metricsLabel) } return treatments @@ -321,12 +321,12 @@ func (c *SplitClient) Treatments(key interface{}, featureFlagNames []string, att return treatmentsResult } -func (c *SplitClient) validateSets(sets []string) []string { - if len(sets) == 0 { +func (c *SplitClient) validateSets(flagSets []string) []string { + if len(flagSets) == 0 { c.logger.Warning("sets must be a non-empty array") return nil } - sets, errs := flagsets.SanitizeMany(sets) + flagSets, errs := flagsets.SanitizeMany(flagSets) if len(errs) != 0 { for _, err := range errs { if errType, ok := err.(*dtos.FlagSetValidatonError); ok { @@ -334,17 +334,17 @@ func (c *SplitClient) validateSets(sets []string) []string { } } } - sets = c.filterSetsAreInConfig(sets) - if len(sets) == 0 { + flagSets = c.filterSetsAreInConfig(flagSets) + if len(flagSets) == 0 { return nil } - return sets + return flagSets } // Treatments evaluate multiple feature flag names belonging to a flag set for a single user and a set of attributes at once -func (c *SplitClient) TreatmentsByFlagSet(key interface{}, set string, attributes map[string]interface{}) map[string]string { +func (c *SplitClient) TreatmentsByFlagSet(key interface{}, flagSet string, attributes map[string]interface{}) map[string]string { treatmentsResult := map[string]string{} - sets := c.validateSets([]string{set}) + sets := c.validateSets([]string{flagSet}) if sets == nil { return treatmentsResult } @@ -356,22 +356,22 @@ func (c *SplitClient) TreatmentsByFlagSet(key interface{}, set string, attribute } // Treatments evaluate multiple feature flag names belonging to flag sets for a single user and a set of attributes at once -func (c *SplitClient) TreatmentsByFlagSets(key interface{}, sets []string, attributes map[string]interface{}) map[string]string { +func (c *SplitClient) TreatmentsByFlagSets(key interface{}, flagSets []string, attributes map[string]interface{}) map[string]string { treatmentsResult := map[string]string{} - sets = c.validateSets(sets) - if sets == nil { + flagSets = c.validateSets(flagSets) + if flagSets == nil { return treatmentsResult } - result := c.doTreatmentsCallByFlagSets(key, sets, attributes, treatmentsByFlagSets, telemetry.TreatmentsByFlagSets) + result := c.doTreatmentsCallByFlagSets(key, flagSets, attributes, treatmentsByFlagSets, telemetry.TreatmentsByFlagSets) for feature, treatmentResult := range result { treatmentsResult[feature] = treatmentResult.Treatment } return treatmentsResult } -func (c *SplitClient) filterSetsAreInConfig(sets []string) []string { +func (c *SplitClient) filterSetsAreInConfig(flagSets []string) []string { toReturn := []string{} - for _, flagSet := range sets { + for _, flagSet := range flagSets { if !c.flagSetsFilter.IsPresent(flagSet) { c.logger.Warning(fmt.Sprintf("you passed %s which is not part of the configured FlagSetsFilter, ignoring Flag Set.", flagSet)) continue @@ -387,9 +387,9 @@ func (c *SplitClient) TreatmentsWithConfig(key interface{}, featureFlagNames []s } // TreatmentsWithConfigByFlagSet evaluates multiple feature flag names belonging to a flag set for a single user and set of attributes at once and returns configurations -func (c *SplitClient) TreatmentsWithConfigByFlagSet(key interface{}, set string, attributes map[string]interface{}) map[string]TreatmentResult { +func (c *SplitClient) TreatmentsWithConfigByFlagSet(key interface{}, flagSet string, attributes map[string]interface{}) map[string]TreatmentResult { treatmentsResult := make(map[string]TreatmentResult) - sets := c.validateSets([]string{set}) + sets := c.validateSets([]string{flagSet}) if sets == nil { return treatmentsResult } @@ -397,13 +397,13 @@ func (c *SplitClient) TreatmentsWithConfigByFlagSet(key interface{}, set string, } // TreatmentsWithConfigByFlagSet evaluates multiple feature flag names belonging to a flag sets for a single user and set of attributes at once and returns configurations -func (c *SplitClient) TreatmentsWithConfigByFlagSets(key interface{}, sets []string, attributes map[string]interface{}) map[string]TreatmentResult { +func (c *SplitClient) TreatmentsWithConfigByFlagSets(key interface{}, flagSets []string, attributes map[string]interface{}) map[string]TreatmentResult { treatmentsResult := make(map[string]TreatmentResult) - sets = c.validateSets(sets) - if sets == nil { + flagSets = c.validateSets(flagSets) + if flagSets == nil { return treatmentsResult } - return c.doTreatmentsCallByFlagSets(key, sets, attributes, treatmentsWithConfigByFlagSets, telemetry.TreatmentsByFlagSets) + return c.doTreatmentsCallByFlagSets(key, flagSets, attributes, treatmentsWithConfigByFlagSets, telemetry.TreatmentsByFlagSets) } // isDestroyed returns true if the client has been destroyed From 758be91d36f728dcc8116fd5a71c6d5b4b4e5539 Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Thu, 16 Nov 2023 11:24:23 -0300 Subject: [PATCH 08/19] [SDKS-7683] Set init config telemetry with FlagSetsTotal and FlagSetsInvalid --- go.mod | 2 +- go.sum | 4 ++-- splitio/client/factory.go | 27 ++++++++++++++++----------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index cd4331f..944fe4d 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/splitio/go-client/v6 go 1.18 require ( - github.com/splitio/go-split-commons/v5 v5.0.1-0.20231114174555-e7fa17527a05 + github.com/splitio/go-split-commons/v5 v5.0.1-0.20231115165340-19ae11b6b7d5 github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc ) diff --git a/go.sum b/go.sum index 907f417..de223f6 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/redis/go-redis/v9 v9.0.4 h1:FC82T+CHJ/Q/PdyLW++GeCO+Ol59Y4T7R4jbgjvktgc= github.com/redis/go-redis/v9 v9.0.4/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= -github.com/splitio/go-split-commons/v5 v5.0.1-0.20231114174555-e7fa17527a05 h1:rDWd6xVhU/XCmWH28+8CnWkJOZ+8yoKxm2+rbX3HahI= -github.com/splitio/go-split-commons/v5 v5.0.1-0.20231114174555-e7fa17527a05/go.mod h1:PSkBLDXQW7NAhZ7JO1va7QJyTeDvpE7MEDnTdn5evRM= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231115165340-19ae11b6b7d5 h1:tXHXzigms5Umk2HCOv72QqXGVypNSrzpl6E0Mwpxoq4= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231115165340-19ae11b6b7d5/go.mod h1:PSkBLDXQW7NAhZ7JO1va7QJyTeDvpE7MEDnTdn5evRM= github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc h1:14jdJE/rBEYfs1CO8kOQrj/8azszRFU4yw5FQIGpoJg= github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= diff --git a/splitio/client/factory.go b/splitio/client/factory.go index 48d35ed..3db2471 100644 --- a/splitio/client/factory.go +++ b/splitio/client/factory.go @@ -133,25 +133,25 @@ func (f *SplitFactory) IsReady() bool { } // initializates tasks for in-memory mode -func (f *SplitFactory) initializationManager(readyChannel chan int) { +func (f *SplitFactory) initializationManager(readyChannel chan int, flagSetsInvalid int64) { go f.syncManager.Start() msg := <-readyChannel switch msg { case synchronizer.Ready: // Broadcast ready status for SDK - f.broadcastReadiness(sdkStatusReady, make([]string, 0)) + f.broadcastReadiness(sdkStatusReady, make([]string, 0), flagSetsInvalid) default: - f.broadcastReadiness(sdkInitializationFailed, make([]string, 0)) + f.broadcastReadiness(sdkInitializationFailed, make([]string, 0), flagSetsInvalid) } } -func (f *SplitFactory) initializationRedis() { +func (f *SplitFactory) initializationRedis(flagSetsInvalid int64) { go f.syncManager.Start() - f.broadcastReadiness(sdkStatusReady, make([]string, 0)) + f.broadcastReadiness(sdkStatusReady, make([]string, 0), flagSetsInvalid) } // recordInitTelemetry In charge of recording init stats from redis and memory -func (f *SplitFactory) recordInitTelemetry(tags []string, currentFactories map[string]int64) { +func (f *SplitFactory) recordInitTelemetry(tags []string, currentFactories map[string]int64, flagSetsInvalid int64) { f.logger.Debug("Sending init telemetry") f.telemetrySync.SynchronizeConfig( telemetry.InitConfig{ @@ -173,6 +173,8 @@ func (f *SplitFactory) recordInitTelemetry(tags []string, currentFactories map[s TaskPeriods: config.TaskPeriods(f.cfg.TaskPeriods), ImpressionsMode: f.cfg.ImpressionsMode, ListenerEnabled: f.cfg.Advanced.ImpressionListener != nil, + FlagSetsTotal: int64(len(f.cfg.Advanced.FlagSetFilter)), + FlagSetsInvalid: flagSetsInvalid, }, time.Now().UTC().Sub(f.startTime).Milliseconds(), currentFactories, @@ -181,7 +183,7 @@ func (f *SplitFactory) recordInitTelemetry(tags []string, currentFactories map[s } // broadcastReadiness broadcasts message to all the subscriptors -func (f *SplitFactory) broadcastReadiness(status int, tags []string) { +func (f *SplitFactory) broadcastReadiness(status int, tags []string, flagSetsInvalid int64) { f.mutex.Lock() defer f.mutex.Unlock() if f.status.Load() == sdkStatusInitializing && status == sdkStatusReady { @@ -191,7 +193,7 @@ func (f *SplitFactory) broadcastReadiness(status int, tags []string) { subscriptor <- status } // At this point the SDK is ready for sending telemetry - go f.recordInitTelemetry(tags, getFactories()) + go f.recordInitTelemetry(tags, getFactories(), flagSetsInvalid) } // subscribes listener @@ -286,6 +288,7 @@ func setupInMemoryFactory( ) (*SplitFactory, error) { advanced, warnings := conf.NormalizeSDKConf(cfg.Advanced) printWarnings(logger, warnings) + flagSetsInvalid := int64(len(cfg.Advanced.FlagSetFilter) - len(advanced.FlagSetsFilter)) if strings.TrimSpace(cfg.SplitSyncProxyURL) != "" { advanced.StreamingEnabled = false } @@ -380,7 +383,7 @@ func setupInMemoryFactory( splitFactory.status.Store(sdkStatusInitializing) setFactory(splitFactory.apikey, splitFactory.logger) - go splitFactory.initializationManager(readyChannel) + go splitFactory.initializationManager(readyChannel, flagSetsInvalid) return &splitFactory, nil } @@ -402,6 +405,7 @@ func setupRedisFactory(apikey string, cfg *conf.SplitSdkConfig, logger logging.L impressionStorage := redis.NewImpressionStorage(redisClient, metadata, logger) flagSets, errs := flagsets.SanitizeMany(cfg.Advanced.FlagSetFilter) + flagSetsInvalid := int64(len(cfg.Advanced.FlagSetFilter) - len(flagSets)) printWarnings(logger, errs) flagSetFilter := flagsets.NewFlagSetFilter(flagSets) @@ -456,7 +460,7 @@ func setupRedisFactory(apikey string, cfg *conf.SplitSdkConfig, logger logging.L factory.status.Store(sdkStatusInitializing) setFactory(factory.apikey, factory.logger) - factory.initializationRedis() + factory.initializationRedis(flagSetsInvalid) return factory, nil } @@ -468,6 +472,7 @@ func setupLocalhostFactory( metadata dtos.Metadata, ) (*SplitFactory, error) { flagSets, errs := flagsets.SanitizeMany(cfg.Advanced.FlagSetFilter) + flagSetsInvalid := int64(len(cfg.Advanced.FlagSetFilter) - len(flagSets)) printWarnings(logger, errs) flagSetFilter := flagsets.NewFlagSetFilter(flagSets) splitStorage := mutexmap.NewMMSplitStorage(flagSetFilter) @@ -542,7 +547,7 @@ func setupLocalhostFactory( setFactory(splitFactory.apikey, splitFactory.logger) // Call fetching tasks as goroutine - go splitFactory.initializationManager(readyChannel) + go splitFactory.initializationManager(readyChannel, flagSetsInvalid) return splitFactory, nil } From 92b7f52a41a34c0908fb260e89c27415823e3c62 Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Thu, 16 Nov 2023 12:31:32 -0300 Subject: [PATCH 09/19] [SDKS-7685] Add sets in SplitView --- splitio/client/manager.go | 6 ++++++ splitio/client/manager_test.go | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/splitio/client/manager.go b/splitio/client/manager.go index db35ab9..c9cb71c 100644 --- a/splitio/client/manager.go +++ b/splitio/client/manager.go @@ -25,6 +25,7 @@ type SplitView struct { Treatments []string `json:"treatments"` ChangeNumber int64 `json:"changeNumber"` Configs map[string]string `json:"configs"` + Sets []string `json:"sets"` } func newSplitView(splitDto *dtos.SplitDTO) *SplitView { @@ -34,6 +35,10 @@ func newSplitView(splitDto *dtos.SplitDTO) *SplitView { treatments = append(treatments, partition.Treatment) } } + sets := []string{} + if splitDto.Sets != nil { + sets = splitDto.Sets + } return &SplitView{ ChangeNumber: splitDto.ChangeNumber, Killed: splitDto.Killed, @@ -41,6 +46,7 @@ func newSplitView(splitDto *dtos.SplitDTO) *SplitView { TrafficType: splitDto.TrafficTypeName, Treatments: treatments, Configs: splitDto.Configurations, + Sets: sets, } } diff --git a/splitio/client/manager_test.go b/splitio/client/manager_test.go index 12d03ac..9f7d85d 100644 --- a/splitio/client/manager_test.go +++ b/splitio/client/manager_test.go @@ -19,6 +19,7 @@ func TestSplitManager(t *testing.T) { Name: "split1", Killed: false, TrafficTypeName: "tt1", + Sets: []string{"set1", "set2"}, Conditions: []dtos.ConditionDTO{ { Partitions: []dtos.PartitionDTO{ @@ -71,6 +72,10 @@ func TestSplitManager(t *testing.T) { t.Error("Incorrect treatments for split 1") } + if len(s1.Sets) != 2 { + t.Error("split1 should have 2 sets") + } + s2 := manager.Split("split2") if s2.Name != "split2" || !s2.Killed || s2.TrafficType != "tt2" || s2.ChangeNumber != 123 { t.Error("Split 2 stored incorrectly") @@ -79,6 +84,10 @@ func TestSplitManager(t *testing.T) { t.Error("Incorrect treatments for split 2") } + if s2.Sets == nil && len(s2.Sets) != 0 { + t.Error("split2 sets should be empty array") + } + all := manager.Splits() if len(all) != 2 { t.Error("Incorrect number of splits returned") From e8e314e9e6d4c8e51e11882456eab2bda7ecd164 Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Tue, 21 Nov 2023 11:48:46 -0300 Subject: [PATCH 10/19] [SDKS-7633] Add default treatment in SplitView --- splitio/client/manager.go | 30 ++++++++++++++++-------------- splitio/client/manager_test.go | 24 +++++++++++++++++++----- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/splitio/client/manager.go b/splitio/client/manager.go index c9cb71c..756340b 100644 --- a/splitio/client/manager.go +++ b/splitio/client/manager.go @@ -19,13 +19,14 @@ type SplitManager struct { // SplitView is a partial representation of a currently stored split type SplitView struct { - Name string `json:"name"` - TrafficType string `json:"trafficType"` - Killed bool `json:"killed"` - Treatments []string `json:"treatments"` - ChangeNumber int64 `json:"changeNumber"` - Configs map[string]string `json:"configs"` - Sets []string `json:"sets"` + Name string `json:"name"` + TrafficType string `json:"trafficType"` + Killed bool `json:"killed"` + Treatments []string `json:"treatments"` + ChangeNumber int64 `json:"changeNumber"` + Configs map[string]string `json:"configs"` + DefaultTreatment string `json:"defaultTreatment"` + Sets []string `json:"sets"` } func newSplitView(splitDto *dtos.SplitDTO) *SplitView { @@ -40,13 +41,14 @@ func newSplitView(splitDto *dtos.SplitDTO) *SplitView { sets = splitDto.Sets } return &SplitView{ - ChangeNumber: splitDto.ChangeNumber, - Killed: splitDto.Killed, - Name: splitDto.Name, - TrafficType: splitDto.TrafficTypeName, - Treatments: treatments, - Configs: splitDto.Configurations, - Sets: sets, + ChangeNumber: splitDto.ChangeNumber, + Killed: splitDto.Killed, + Name: splitDto.Name, + TrafficType: splitDto.TrafficTypeName, + Treatments: treatments, + Configs: splitDto.Configurations, + DefaultTreatment: splitDto.DefaultTreatment, + Sets: sets, } } diff --git a/splitio/client/manager_test.go b/splitio/client/manager_test.go index 9f7d85d..9708101 100644 --- a/splitio/client/manager_test.go +++ b/splitio/client/manager_test.go @@ -15,11 +15,12 @@ func TestSplitManager(t *testing.T) { splitStorage := mutexmap.NewMMSplitStorage(flagSetFilter) splitStorage.Update([]dtos.SplitDTO{ { - ChangeNumber: 123, - Name: "split1", - Killed: false, - TrafficTypeName: "tt1", - Sets: []string{"set1", "set2"}, + ChangeNumber: 123, + Name: "split1", + Killed: false, + TrafficTypeName: "tt1", + Sets: []string{"set1", "set2"}, + DefaultTreatment: "s1p1", Conditions: []dtos.ConditionDTO{ { Partitions: []dtos.PartitionDTO{ @@ -76,6 +77,10 @@ func TestSplitManager(t *testing.T) { t.Error("split1 should have 2 sets") } + if s1.DefaultTreatment != "s1p1" { + t.Error("the default treatment for split1 should be s1p1") + } + s2 := manager.Split("split2") if s2.Name != "split2" || !s2.Killed || s2.TrafficType != "tt2" || s2.ChangeNumber != 123 { t.Error("Split 2 stored incorrectly") @@ -135,6 +140,9 @@ func TestSplitManagerWithConfigs(t *testing.T) { if s1.Configs["on"] != "{\"color\": \"blue\",\"size\": 13}" { t.Error("It should have configs") } + if s1.DefaultTreatment != "off" { + t.Error("the default treatment for valid should be off") + } s2 := manager.Split("killed") if s2.Name != "killed" || !s2.Killed || s2.TrafficType != "user" || s2.ChangeNumber != 1494593336752 { @@ -149,6 +157,9 @@ func TestSplitManagerWithConfigs(t *testing.T) { if s2.Configs["defTreatment"] != "{\"color\": \"orange\",\"size\": 15}" { t.Error("It should have configs") } + if s2.DefaultTreatment != "defTreatment" { + t.Error("the default treatment for killed should be defTreatment") + } s3 := manager.Split("noConfig") if s3.Name != "noConfig" || s3.Killed || s3.TrafficType != "user" || s3.ChangeNumber != 1494593336752 { @@ -160,6 +171,9 @@ func TestSplitManagerWithConfigs(t *testing.T) { if s3.Configs != nil { t.Error("It should not have configs") } + if s3.DefaultTreatment != "defTreatment" { + t.Error("the default treatment for killed should be defTreatment") + } all := manager.Splits() if len(all) != 3 { From 457e3960eedda300cd086b333c163dfd30d0678e Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Tue, 21 Nov 2023 16:50:34 -0300 Subject: [PATCH 11/19] [SDKS-7625] Add feature flag name in ready warning log --- splitio/client/client.go | 7 +++++-- splitio/client/input_validator_test.go | 11 ++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/splitio/client/client.go b/splitio/client/client.go index e4dfd39..7d8f7c0 100644 --- a/splitio/client/client.go +++ b/splitio/client/client.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "runtime/debug" + "strings" "time" "github.com/splitio/go-client/v6/splitio/conf" @@ -57,7 +58,8 @@ func (c *SplitClient) getEvaluationResult(matchingKey string, bucketingKey *stri if c.isReady() { return c.evaluator.EvaluateFeature(matchingKey, bucketingKey, featureFlag, attributes) } - c.logger.Warning(operation + ": the SDK is not ready, results may be incorrect. Make sure to wait for SDK readiness before using this method") + + c.logger.Warning(fmt.Sprintf("%s: the SDK is not ready, results may be incorrect for feature flag %s. Make sure to wait for SDK readiness before using this method", operation, featureFlag)) c.initTelemetry.RecordNonReadyUsage() return &evaluator.Result{ Treatment: evaluator.Control, @@ -71,7 +73,8 @@ func (c *SplitClient) getEvaluationsResult(matchingKey string, bucketingKey *str if c.isReady() { return c.evaluator.EvaluateFeatures(matchingKey, bucketingKey, featureFlags, attributes) } - c.logger.Warning(operation + ": the SDK is not ready, results may be incorrect. Make sure to wait for SDK readiness before using this method") + featureFlagsToPrint := strings.Join(featureFlags, ",") + c.logger.Warning(fmt.Sprintf("%s: the SDK is not ready, results may be incorrect for feature flag %s. Make sure to wait for SDK readiness before using this method", operation, featureFlagsToPrint)) c.initTelemetry.RecordNonReadyUsage() result := evaluator.Results{ EvaluationTime: 0, diff --git a/splitio/client/input_validator_test.go b/splitio/client/input_validator_test.go index 73e401a..0344dc0 100644 --- a/splitio/client/input_validator_test.go +++ b/splitio/client/input_validator_test.go @@ -554,27 +554,28 @@ func TestNotReadyYet(t *testing.T) { factoryNotReady.status.Store(sdkStatusInitializing) expectedMessage := "{operation}: the SDK is not ready, results may be incorrect. Make sure to wait for SDK readiness before using this method" + expectedMessage1 := "{operation}: the SDK is not ready, results may be incorrect for feature flag feature. Make sure to wait for SDK readiness before using this method" + expectedMessage2 := "{operation}: the SDK is not ready, results may be incorrect for feature flag feature,feature_2. Make sure to wait for SDK readiness before using this method" clientNotReady.Treatment("test", "feature", nil) - if !mW.Matches(strings.Replace(expectedMessage, "{operation}", "Treatment", 1)) { + if !mW.Matches(strings.Replace(expectedMessage1, "{operation}", "Treatment", 1)) { t.Error("Wrong message") } clientNotReady.Treatments("test", []string{"feature", "feature_2"}, nil) - if !mW.Matches(strings.Replace(expectedMessage, "{operation}", "Treatments", 1)) { + if !mW.Matches(strings.Replace(expectedMessage2, "{operation}", "Treatments", 1)) { t.Error("Wrong message") } clientNotReady.TreatmentWithConfig("test", "feature", nil) - if !mW.Matches(strings.Replace(expectedMessage, "{operation}", "TreatmentWithConfig", 1)) { + if !mW.Matches(strings.Replace(expectedMessage1, "{operation}", "TreatmentWithConfig", 1)) { t.Error("Wrong message") } clientNotReady.TreatmentsWithConfig("test", []string{"feature", "feature_2"}, nil) - if !mW.Matches(strings.Replace(expectedMessage, "{operation}", "TreatmentsWithConfig", 1)) { + if !mW.Matches(strings.Replace(expectedMessage2, "{operation}", "TreatmentsWithConfig", 1)) { t.Error("Wrong message") } - expected := "Track: the SDK is not ready, results may be incorrect. Make sure to wait for SDK readiness before using this method" expectedTrack(clientNotReady.Track("key", "traffic", "eventType", nil, nil), expected, t) From 55dd7c78f4061194768fcd0165ed000cb8d7457c Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Tue, 21 Nov 2023 17:26:27 -0300 Subject: [PATCH 12/19] [SDKS-7625] Pr suggestion --- splitio/client/client.go | 4 ++-- splitio/client/input_validator_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/splitio/client/client.go b/splitio/client/client.go index 7d8f7c0..c6988c6 100644 --- a/splitio/client/client.go +++ b/splitio/client/client.go @@ -73,8 +73,8 @@ func (c *SplitClient) getEvaluationsResult(matchingKey string, bucketingKey *str if c.isReady() { return c.evaluator.EvaluateFeatures(matchingKey, bucketingKey, featureFlags, attributes) } - featureFlagsToPrint := strings.Join(featureFlags, ",") - c.logger.Warning(fmt.Sprintf("%s: the SDK is not ready, results may be incorrect for feature flag %s. Make sure to wait for SDK readiness before using this method", operation, featureFlagsToPrint)) + featureFlagsToPrint := strings.Join(featureFlags, ", ") + c.logger.Warning(fmt.Sprintf("%s: the SDK is not ready, results may be incorrect for feature flags %s. Make sure to wait for SDK readiness before using this method", operation, featureFlagsToPrint)) c.initTelemetry.RecordNonReadyUsage() result := evaluator.Results{ EvaluationTime: 0, diff --git a/splitio/client/input_validator_test.go b/splitio/client/input_validator_test.go index 0344dc0..f6a5f99 100644 --- a/splitio/client/input_validator_test.go +++ b/splitio/client/input_validator_test.go @@ -555,7 +555,7 @@ func TestNotReadyYet(t *testing.T) { expectedMessage := "{operation}: the SDK is not ready, results may be incorrect. Make sure to wait for SDK readiness before using this method" expectedMessage1 := "{operation}: the SDK is not ready, results may be incorrect for feature flag feature. Make sure to wait for SDK readiness before using this method" - expectedMessage2 := "{operation}: the SDK is not ready, results may be incorrect for feature flag feature,feature_2. Make sure to wait for SDK readiness before using this method" + expectedMessage2 := "{operation}: the SDK is not ready, results may be incorrect for feature flags feature, feature_2. Make sure to wait for SDK readiness before using this method" clientNotReady.Treatment("test", "feature", nil) if !mW.Matches(strings.Replace(expectedMessage1, "{operation}", "Treatment", 1)) { From c428b468e671b069670311fc4ba1cc672dc53ca8 Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Fri, 24 Nov 2023 11:50:14 -0300 Subject: [PATCH 13/19] [SDKS-7687] Add test to validate flag sets when fetch ff --- go.mod | 2 +- go.sum | 2 + splitio/client/input_validator_test.go | 85 ++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 944fe4d..3c10469 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/splitio/go-client/v6 go 1.18 require ( - github.com/splitio/go-split-commons/v5 v5.0.1-0.20231115165340-19ae11b6b7d5 + github.com/splitio/go-split-commons/v5 v5.0.1-0.20231122221702-e3b2ef60041d github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc ) diff --git a/go.sum b/go.sum index de223f6..f2a68e2 100644 --- a/go.sum +++ b/go.sum @@ -12,6 +12,8 @@ github.com/redis/go-redis/v9 v9.0.4 h1:FC82T+CHJ/Q/PdyLW++GeCO+Ol59Y4T7R4jbgjvkt github.com/redis/go-redis/v9 v9.0.4/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= github.com/splitio/go-split-commons/v5 v5.0.1-0.20231115165340-19ae11b6b7d5 h1:tXHXzigms5Umk2HCOv72QqXGVypNSrzpl6E0Mwpxoq4= github.com/splitio/go-split-commons/v5 v5.0.1-0.20231115165340-19ae11b6b7d5/go.mod h1:PSkBLDXQW7NAhZ7JO1va7QJyTeDvpE7MEDnTdn5evRM= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231122221702-e3b2ef60041d h1:Xt94/BkqILwbU65m8yDauU7khOpeFBbzGXrS6CKgOfs= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231122221702-e3b2ef60041d/go.mod h1:PSkBLDXQW7NAhZ7JO1va7QJyTeDvpE7MEDnTdn5evRM= github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc h1:14jdJE/rBEYfs1CO8kOQrj/8azszRFU4yw5FQIGpoJg= github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= diff --git a/splitio/client/input_validator_test.go b/splitio/client/input_validator_test.go index f6a5f99..9a4ad78 100644 --- a/splitio/client/input_validator_test.go +++ b/splitio/client/input_validator_test.go @@ -1,9 +1,14 @@ package client import ( + "compress/gzip" + "encoding/json" "fmt" + "io/ioutil" "math" "math/rand" + "net/http" + "net/http/httptest" "strings" "sync" "testing" @@ -518,6 +523,86 @@ func TestLocalhostTrafficType(t *testing.T) { mW.Reset() } +func TestInMemoryFactoryFlagSets(t *testing.T) { + var splitsMock, _ = ioutil.ReadFile("../../testdata/splits_mock.json") + var splitMock, _ = ioutil.ReadFile("../../testdata/split_mock.json") + + postChannel := make(chan string, 1) + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/splitChanges": + if r.RequestURI != "/splitChanges?sets=a%2Cc%2Cd&since=-1" { + t.Error("wrong RequestURI for flag sets") + } + fmt.Fprintln(w, fmt.Sprintf(string(splitsMock), splitMock)) + return + case "/segmentChanges/___TEST___": + w.Header().Add("Content-Encoding", "gzip") + gzw := gzip.NewWriter(w) + defer gzw.Close() + fmt.Fprintln(gzw, "Hello, client") + return + case "/testImpressions/bulk": + case "/events/bulk": + for header := range r.Header { + if (header == "SplitSDKMachineIP") || (header == "SplitSDKMachineName") { + t.Error("Should not insert one of SplitSDKMachineIP, SplitSDKMachineName") + } + } + + rBody, _ := ioutil.ReadAll(r.Body) + var dataInPost []map[string]interface{} + err := json.Unmarshal(rBody, &dataInPost) + if err != nil { + t.Error(err) + return + } + + if len(dataInPost) < 1 { + t.Error("It should send data") + } + fmt.Fprintln(w, "ok") + postChannel <- "finished" + case "/segmentChanges": + default: + fmt.Fprintln(w, "ok") + return + } + })) + defer ts.Close() + cfg := conf.Default() + cfg.LabelsEnabled = true + cfg.IPAddressesEnabled = true + cfg.Advanced.EventsURL = ts.URL + cfg.Advanced.SdkURL = ts.URL + cfg.Advanced.TelemetryServiceURL = ts.URL + cfg.Advanced.AuthServiceURL = ts.URL + cfg.Advanced.ImpressionListener = &ImpressionListenerTest{} + cfg.TaskPeriods.ImpressionSync = 60 + cfg.TaskPeriods.EventsSync = 60 + cfg.Advanced.StreamingEnabled = false + cfg.Advanced.FlagSetFilter = []string{"a", "_b", "a", "a", "c", "d", "_d"} + + factory, _ := NewSplitFactory("test", cfg) + client := factory.Client() + errBlock := client.BlockUntilReady(10) + + if errBlock != nil { + t.Error("client should be ready") + } + + if !client.isReady() { + t.Error("InMemory should be ready") + } + + mW.Reset() + if mW.Length() > 0 { + t.Error("Wrong message") + } + mW.Reset() +} + func TestNotReadyYet(t *testing.T) { nonReadyUsages := 0 logger := getMockedLogger() From b872c6b26ac8b052d50e9dcd9d8b2d2de96aeafb Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Fri, 24 Nov 2023 12:53:47 -0300 Subject: [PATCH 14/19] Set FlagSetsTotal and FlagSetsInvalid to 0 when consumer mode --- go.mod | 2 +- go.sum | 4 ++-- splitio/client/factory.go | 15 ++++++++------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 944fe4d..b6988cf 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/splitio/go-client/v6 go 1.18 require ( - github.com/splitio/go-split-commons/v5 v5.0.1-0.20231115165340-19ae11b6b7d5 + github.com/splitio/go-split-commons/v5 v5.0.1-0.20231124144735-13d1c8dd5c21 github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc ) diff --git a/go.sum b/go.sum index de223f6..1bd2bf3 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/redis/go-redis/v9 v9.0.4 h1:FC82T+CHJ/Q/PdyLW++GeCO+Ol59Y4T7R4jbgjvktgc= github.com/redis/go-redis/v9 v9.0.4/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= -github.com/splitio/go-split-commons/v5 v5.0.1-0.20231115165340-19ae11b6b7d5 h1:tXHXzigms5Umk2HCOv72QqXGVypNSrzpl6E0Mwpxoq4= -github.com/splitio/go-split-commons/v5 v5.0.1-0.20231115165340-19ae11b6b7d5/go.mod h1:PSkBLDXQW7NAhZ7JO1va7QJyTeDvpE7MEDnTdn5evRM= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231124144735-13d1c8dd5c21 h1:7EG7cfNlwqo1X/qKN6J/wMkLFUcurhxp9ZrL5pVTevM= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231124144735-13d1c8dd5c21/go.mod h1:PSkBLDXQW7NAhZ7JO1va7QJyTeDvpE7MEDnTdn5evRM= github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc h1:14jdJE/rBEYfs1CO8kOQrj/8azszRFU4yw5FQIGpoJg= github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= diff --git a/splitio/client/factory.go b/splitio/client/factory.go index 3db2471..54865d3 100644 --- a/splitio/client/factory.go +++ b/splitio/client/factory.go @@ -145,9 +145,9 @@ func (f *SplitFactory) initializationManager(readyChannel chan int, flagSetsInva } } -func (f *SplitFactory) initializationRedis(flagSetsInvalid int64) { +func (f *SplitFactory) initializationRedis() { go f.syncManager.Start() - f.broadcastReadiness(sdkStatusReady, make([]string, 0), flagSetsInvalid) + f.broadcastReadiness(sdkStatusReady, make([]string, 0), 0) } // recordInitTelemetry In charge of recording init stats from redis and memory @@ -404,10 +404,11 @@ func setupRedisFactory(apikey string, cfg *conf.SplitSdkConfig, logger logging.L inMememoryFullQueue := make(chan string, 2) // Size 2: So that it's able to accept one event from each resource simultaneously. impressionStorage := redis.NewImpressionStorage(redisClient, metadata, logger) - flagSets, errs := flagsets.SanitizeMany(cfg.Advanced.FlagSetFilter) - flagSetsInvalid := int64(len(cfg.Advanced.FlagSetFilter) - len(flagSets)) - printWarnings(logger, errs) - flagSetFilter := flagsets.NewFlagSetFilter(flagSets) + if len(cfg.Advanced.FlagSetFilter) != 0 { + cfg.Advanced.FlagSetFilter = []string{} + logger.Debug("FlagSets filter is not applicable for Consumer modes where the SDK does not keep rollout data in sync. FlagSet filter was discarded") + } + flagSetFilter := flagsets.NewFlagSetFilter([]string{}) storages := sdkStorages{ splits: redis.NewSplitStorage(redisClient, logger, flagSetFilter), @@ -460,7 +461,7 @@ func setupRedisFactory(apikey string, cfg *conf.SplitSdkConfig, logger logging.L factory.status.Store(sdkStatusInitializing) setFactory(factory.apikey, factory.logger) - factory.initializationRedis(flagSetsInvalid) + factory.initializationRedis() return factory, nil } From d308e41195d2f21f16d3a12ab66ef4c51508f9f6 Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Mon, 27 Nov 2023 10:17:36 -0300 Subject: [PATCH 15/19] [SDKS-7687] Add test case in input_validator --- splitio/client/factory.go | 2 +- splitio/client/input_validator_test.go | 64 +++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/splitio/client/factory.go b/splitio/client/factory.go index 54865d3..c387446 100644 --- a/splitio/client/factory.go +++ b/splitio/client/factory.go @@ -406,7 +406,7 @@ func setupRedisFactory(apikey string, cfg *conf.SplitSdkConfig, logger logging.L if len(cfg.Advanced.FlagSetFilter) != 0 { cfg.Advanced.FlagSetFilter = []string{} - logger.Debug("FlagSets filter is not applicable for Consumer modes where the SDK does not keep rollout data in sync. FlagSet filter was discarded") + logger.Warning("FlagSets filter is not applicable for Consumer modes where the SDK does not keep rollout data in sync. FlagSet filter was discarded") } flagSetFilter := flagsets.NewFlagSetFilter([]string{}) diff --git a/splitio/client/input_validator_test.go b/splitio/client/input_validator_test.go index 9a4ad78..3a47f7d 100644 --- a/splitio/client/input_validator_test.go +++ b/splitio/client/input_validator_test.go @@ -15,6 +15,7 @@ import ( "time" "github.com/splitio/go-client/v6/splitio/conf" + commonsCfg "github.com/splitio/go-split-commons/v5/conf" spConf "github.com/splitio/go-split-commons/v5/conf" "github.com/splitio/go-split-commons/v5/dtos" "github.com/splitio/go-split-commons/v5/flagsets" @@ -26,6 +27,7 @@ import ( "github.com/splitio/go-split-commons/v5/storage/inmemory/mutexmap" "github.com/splitio/go-split-commons/v5/storage/inmemory/mutexqueue" "github.com/splitio/go-split-commons/v5/storage/mocks" + "github.com/splitio/go-split-commons/v5/storage/redis" "github.com/splitio/go-split-commons/v5/synchronizer" "github.com/splitio/go-toolkit/v5/logging" ) @@ -565,6 +567,20 @@ func TestInMemoryFactoryFlagSets(t *testing.T) { fmt.Fprintln(w, "ok") postChannel <- "finished" case "/segmentChanges": + case "/metrics/config": + rBody, _ := ioutil.ReadAll(r.Body) + var dataInPost dtos.Config + err := json.Unmarshal(rBody, &dataInPost) + if err != nil { + t.Error(err) + return + } + if dataInPost.FlagSetsInvalid != 4 { + t.Error("invalid flag sets should be 4") + } + if dataInPost.FlagSetsTotal != 7 { + t.Error("total flag sets should be 7") + } default: fmt.Fprintln(w, "ok") return @@ -586,7 +602,7 @@ func TestInMemoryFactoryFlagSets(t *testing.T) { factory, _ := NewSplitFactory("test", cfg) client := factory.Client() - errBlock := client.BlockUntilReady(10) + errBlock := client.BlockUntilReady(15) if errBlock != nil { t.Error("client should be ready") @@ -601,6 +617,52 @@ func TestInMemoryFactoryFlagSets(t *testing.T) { t.Error("Wrong message") } mW.Reset() + + client.Destroy() +} + +func TestConsumerFactoryFlagSets(t *testing.T) { + logger := getMockedLogger() + sdkConf := conf.Default() + sdkConf.OperationMode = conf.RedisConsumer + sdkConf.Advanced.FlagSetFilter = []string{"a", "b"} + sdkConf.Logger = logger + + factory, _ := NewSplitFactory("something", sdkConf) + if !mW.Matches("FlagSets filter is not applicable for Consumer modes where the SDK does not keep rollout data in sync. FlagSet filter was discarded") { + t.Error("Wrong message") + } + if !factory.IsReady() { + t.Error("Factory should be ready immediately") + } + client := factory.Client() + if !client.factory.IsReady() { + t.Error("Client should be ready immediately") + } + + err := client.BlockUntilReady(1) + if err != nil { + t.Error("Error was not expected") + } + + manager := factory.Manager() + if !manager.factory.IsReady() { + t.Error("Manager should be ready immediately") + } + err = manager.BlockUntilReady(1) + if err != nil { + t.Error("Error was not expected") + } + + prefixedClient, _ := redis.NewRedisClient(&commonsCfg.RedisConfig{ + Host: "localhost", + Port: 6379, + Password: "", + Prefix: "", + }, logging.NewLogger(&logging.LoggerOptions{})) + deleteDataGenerated(prefixedClient) + + client.Destroy() } func TestNotReadyYet(t *testing.T) { From e9dbaefa5a555d6aeb1ed152f7136831f542bfb4 Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Mon, 27 Nov 2023 17:18:42 -0300 Subject: [PATCH 16/19] Udate common version --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b6988cf..de302b8 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/splitio/go-client/v6 go 1.18 require ( - github.com/splitio/go-split-commons/v5 v5.0.1-0.20231124144735-13d1c8dd5c21 + github.com/splitio/go-split-commons/v5 v5.0.1-0.20231127201600-8804da360fcd github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc ) diff --git a/go.sum b/go.sum index 1bd2bf3..e1e968c 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/redis/go-redis/v9 v9.0.4 h1:FC82T+CHJ/Q/PdyLW++GeCO+Ol59Y4T7R4jbgjvktgc= github.com/redis/go-redis/v9 v9.0.4/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= -github.com/splitio/go-split-commons/v5 v5.0.1-0.20231124144735-13d1c8dd5c21 h1:7EG7cfNlwqo1X/qKN6J/wMkLFUcurhxp9ZrL5pVTevM= -github.com/splitio/go-split-commons/v5 v5.0.1-0.20231124144735-13d1c8dd5c21/go.mod h1:PSkBLDXQW7NAhZ7JO1va7QJyTeDvpE7MEDnTdn5evRM= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231127201600-8804da360fcd h1:dO+24M847lygx9lvbKcehyrW09CL+EF0jGxAvO38e5g= +github.com/splitio/go-split-commons/v5 v5.0.1-0.20231127201600-8804da360fcd/go.mod h1:PSkBLDXQW7NAhZ7JO1va7QJyTeDvpE7MEDnTdn5evRM= github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc h1:14jdJE/rBEYfs1CO8kOQrj/8azszRFU4yw5FQIGpoJg= github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= From 0d30b2c0d87e0afddf58a601ca3c16645b39c024 Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Tue, 28 Nov 2023 11:19:10 -0300 Subject: [PATCH 17/19] Update version for tapps --- splitio/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/splitio/version.go b/splitio/version.go index 87adead..516775b 100644 --- a/splitio/version.go +++ b/splitio/version.go @@ -1,4 +1,4 @@ package splitio // Version contains a string with the split sdk version -const Version = "6.4.0" +const Version = "6.5.0-rc1" From 318d83ba1712c6780ec79cb74c352e9a7e201397 Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Wed, 29 Nov 2023 11:35:47 -0300 Subject: [PATCH 18/19] Update commons version and change logs --- CHANGES.txt | 10 ++++++++++ go.mod | 4 ++-- go.sum | 8 ++++---- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 0dd3cdd..4892d42 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,13 @@ +6.5.0 (Nov 29, 2023) +- Added support for Flag Sets on the SDK, which enables grouping feature flags and interacting with the group rather than individually (more details in our documentation): + - Added new variations of the get treatment methods to support evaluating flags in given flag set/s. + - TreatmentsByFlagSet and TreatmentsByFlagSets + - TreatmentsWithConfigByFlagSet and TreatmentsWithConfigByFlagSets + - Added a new optional Flag Sets Filter configuration option. This allows the SDK and Split services to only synchronize the flags in the specified flag sets, avoiding unused or unwanted flags from being synced on the SDK instance, bringing all the benefits from a reduced payload. + - Note: Only applicable when the SDK is in charge of the rollout data synchronization. When not applicable, the SDK will log a warning on init. + - Updated the following SDK manager methods to expose flag sets on flag views. + - Added `DefaultTreatment` property to the `SplitView` object returned by the `Split` and `Splits` functions of the SDK manager. + 6.4.0 (Jul 18, 2023) - Improved streaming architecture implementation to apply feature flag updates from the notification received which is now enhanced, improving efficiency and reliability of the whole update system. - Pointed to new version of go-split-commons v5.0.0. diff --git a/go.mod b/go.mod index de302b8..7ed1f92 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/splitio/go-client/v6 go 1.18 require ( - github.com/splitio/go-split-commons/v5 v5.0.1-0.20231127201600-8804da360fcd - github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc + github.com/splitio/go-split-commons/v5 v5.1.0 + github.com/splitio/go-toolkit/v5 v5.3.2 ) require ( diff --git a/go.sum b/go.sum index e1e968c..ee5e61c 100644 --- a/go.sum +++ b/go.sum @@ -10,10 +10,10 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/r github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/redis/go-redis/v9 v9.0.4 h1:FC82T+CHJ/Q/PdyLW++GeCO+Ol59Y4T7R4jbgjvktgc= github.com/redis/go-redis/v9 v9.0.4/go.mod h1:WqMKv5vnQbRuZstUwxQI195wHy+t4PuXDOjzMvcuQHk= -github.com/splitio/go-split-commons/v5 v5.0.1-0.20231127201600-8804da360fcd h1:dO+24M847lygx9lvbKcehyrW09CL+EF0jGxAvO38e5g= -github.com/splitio/go-split-commons/v5 v5.0.1-0.20231127201600-8804da360fcd/go.mod h1:PSkBLDXQW7NAhZ7JO1va7QJyTeDvpE7MEDnTdn5evRM= -github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc h1:14jdJE/rBEYfs1CO8kOQrj/8azszRFU4yw5FQIGpoJg= -github.com/splitio/go-toolkit/v5 v5.3.2-0.20231106173125-49e72b9823dc/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= +github.com/splitio/go-split-commons/v5 v5.1.0 h1:mki1235gjXwuxcXdv/bKVduX1Lv09uXJogds+BspqSM= +github.com/splitio/go-split-commons/v5 v5.1.0/go.mod h1:9vAZrlhKvhensyRC11hyVFdgLIBrkX9D5vdYc9qB13w= +github.com/splitio/go-toolkit/v5 v5.3.2 h1:Yy9YBcHRmK5WVZjeA/klLGEdF38xpsL1ejnC3ro8a2M= +github.com/splitio/go-toolkit/v5 v5.3.2/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko= github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= From aab3ed39dd196b07c99e9144ff582d0d737d0edf Mon Sep 17 00:00:00 2001 From: Nadia Mayor Date: Wed, 29 Nov 2023 17:33:51 -0300 Subject: [PATCH 19/19] Update version --- splitio/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/splitio/version.go b/splitio/version.go index 516775b..65db916 100644 --- a/splitio/version.go +++ b/splitio/version.go @@ -1,4 +1,4 @@ package splitio // Version contains a string with the split sdk version -const Version = "6.5.0-rc1" +const Version = "6.5.0"