Skip to content

Commit

Permalink
Merge pull request #218 from splitio/SDKS-8369
Browse files Browse the repository at this point in the history
Add test cases for semver and unsupported matcher
  • Loading branch information
nmayorsplit authored May 13, 2024
2 parents 21cbbf8 + 680f920 commit 6e3ad55
Show file tree
Hide file tree
Showing 5 changed files with 593 additions and 2 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/splitio/go-client/v6
go 1.18

require (
github.com/splitio/go-split-commons/v5 v5.2.2-0.20240510211202-3c3300ae55ce
github.com/splitio/go-split-commons/v5 v5.2.2-0.20240513192200-9e60c1ddc0f3
github.com/splitio/go-toolkit/v5 v5.4.0
)

Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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.2.2-0.20240510211202-3c3300ae55ce h1:aZ+p/vi2sOD0NsWCny93qQl1uJC30b/wnpMcUVt7WEI=
github.com/splitio/go-split-commons/v5 v5.2.2-0.20240510211202-3c3300ae55ce/go.mod h1:344KP05ULARzjRfnC4VtGSyu5l3kmIM375WUIzrURs0=
github.com/splitio/go-split-commons/v5 v5.2.2-0.20240513192200-9e60c1ddc0f3 h1:ARgFL9kuUOYX5U1afUbWSMp3fvB7LeWsTDNWWDT9Hl8=
github.com/splitio/go-split-commons/v5 v5.2.2-0.20240513192200-9e60c1ddc0f3/go.mod h1:344KP05ULARzjRfnC4VtGSyu5l3kmIM375WUIzrURs0=
github.com/splitio/go-toolkit/v5 v5.4.0 h1:g5WFpRhQomnXCmvfsNOWV4s5AuUrWIZ+amM68G8NBKM=
github.com/splitio/go-toolkit/v5 v5.4.0/go.mod h1:xYhUvV1gga9/1029Wbp5pjnR6Cy8nvBpjw99wAbsMko=
github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg=
Expand Down
270 changes: 270 additions & 0 deletions splitio/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2114,6 +2114,122 @@ func TestClientDebug(t *testing.T) {
}
}

func TestUnsupportedMatcherAndSemver(t *testing.T) {
var isDestroyCalled = false
var splitsMock, _ = ioutil.ReadFile("../../testdata/splits_mock_3.json")

postChannel := make(chan string, 1)

ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/api/v2/auth":
if r.URL.Query().Get("s") != "1.1" {
t.Error("should be parameter s, for flags spec")
}
fmt.Fprintln(w, "{\"pushEnabled\": false, \"token\": \"token\"}")
return
case "/splitChanges":
fmt.Fprintln(w, string(splitsMock))
return
case "/testImpressions/bulk":
if r.Header.Get("SplitSDKImpressionsMode") != commonsCfg.ImpressionsModeOptimized {
t.Error("Wrong header")
}

if isDestroyCalled {
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) != 6 {
t.Error("It should send two impressions in optimized mode")
}
for _, ki := range dataInPost {
if asISlice, ok := ki["i"].([]interface{}); !ok || len(asISlice) != 1 {
t.Error("It should send only one impression per featureName", dataInPost)
}
if ki["f"] == "unsupported" {
message := ki["i"].([]interface{})[0].(map[string]interface{})["r"]
if message != "targeting rule type unsupported by sdk" {
t.Error("message sould be: targeting rule type unsupported by sdk")
}
}
}
}

fmt.Fprintln(w, "ok")
postChannel <- "finished"
case "/testImpressions/count":
fallthrough
case "/keys/ss":
fallthrough
case "/events/bulk":
fallthrough
case "/segmentChanges":
fallthrough
default:
fmt.Fprintln(w, "ok")
}
}))
defer ts.Close()

cfg := conf.Default()
cfg.Advanced.AuthServiceURL = ts.URL
cfg.Advanced.EventsURL = ts.URL
cfg.Advanced.SdkURL = ts.URL
cfg.Advanced.TelemetryServiceURL = ts.URL

factory, _ := NewSplitFactory("test", cfg)
client := factory.Client()
client.BlockUntilReady(2)

// Calls treatments to generate one valid impression
time.Sleep(300 * time.Millisecond) // Let's wait until first call of recorders have finished
attributes := make(map[string]interface{})
attributes["version"] = "1.22.9"
evaluation := client.Treatment("user1", "semver", attributes)
if evaluation != "on" {
t.Error("evaluation for semver should be on")
}
attributes["version"] = "2.0.0"
evaluation = client.Treatment("user1", "semver1", attributes)
if evaluation != "on" {
t.Error("evaluation for semver should be on")
}
evaluation = client.Treatment("user1", "semver2", attributes)
if evaluation != "on" {
t.Error("evaluation for semver should be on")
}
attributes["version"] = "1.0.0"
evaluation = client.Treatment("user1", "semver3", attributes)
if evaluation != "on" {
t.Error("evaluation for semver should be on")
}
attributes["version"] = "2.1.0"
evaluation = client.Treatment("user1", "semver4", attributes)
if evaluation != "on" {
t.Error("evaluation for semver should be on")
}
evaluation = client.Treatment("user1", "unsupported", nil)
if evaluation != "control" {
t.Error("evaluation for unsupported should be control")
}

isDestroyCalled = true
client.Destroy()

select {
case <-postChannel:
return
case <-time.After(4 * time.Second):
t.Error("The test couldn't send impressions to check headers")
return
}
}

func TestTelemetryMemory(t *testing.T) {
factoryInstances = make(map[string]int64)
var metricsInitCalled int64
Expand Down Expand Up @@ -2633,3 +2749,157 @@ func TestClientDebugRedis(t *testing.T) {
prefixedClient.Del(k)
}
}

var semver string = "3.4.5"
var attribute string = "version"

var splitSemver = &dtos.SplitDTO{
Algo: 2,
ChangeNumber: 1494593336752,
DefaultTreatment: "off",
Killed: false,
Name: "semver",
Seed: -1992295819,
Status: "ACTIVE",
TrafficAllocation: 100,
TrafficAllocationSeed: -285565213,
TrafficTypeName: "user",
Configurations: map[string]string{"on": "{\"color\": \"blue\",\"size\": 13}"},
Conditions: []dtos.ConditionDTO{
{
ConditionType: "ROLLOUT",
Label: "default rule",
MatcherGroup: dtos.MatcherGroupDTO{
Combiner: "AND",
Matchers: []dtos.MatcherDTO{
{
KeySelector: &dtos.KeySelectorDTO{
TrafficType: "user",
Attribute: &attribute,
},
MatcherType: "EQUAL_TO_SEMVER",
String: &semver,
Whitelist: nil,
Negate: false,
},
},
},
Partitions: []dtos.PartitionDTO{
{
Size: 100,
Treatment: "on",
},
{
Size: 0,
Treatment: "off",
},
},
},
},
}

var splitUnsupported = &dtos.SplitDTO{
Algo: 2,
ChangeNumber: 1494593336752,
DefaultTreatment: "off",
Killed: false,
Name: "unsupported",
Seed: -1992295819,
Status: "ACTIVE",
TrafficAllocation: 100,
TrafficAllocationSeed: -285565213,
TrafficTypeName: "user",
Configurations: map[string]string{"on": "{\"color\": \"blue\",\"size\": 13}"},
Conditions: []dtos.ConditionDTO{
{
ConditionType: "ROLLOUT",
Label: "default rule",
MatcherGroup: dtos.MatcherGroupDTO{
Combiner: "AND",
Matchers: []dtos.MatcherDTO{
{
KeySelector: &dtos.KeySelectorDTO{
TrafficType: "user",
Attribute: nil,
},
MatcherType: "UNSUPPORTED",
Whitelist: nil,
Negate: false,
},
},
},
Partitions: []dtos.PartitionDTO{
{
Size: 100,
Treatment: "on",
},
},
},
},
}

func TestUnsupportedandSemverMatcherRedis(t *testing.T) {
redisConfig := &commonsCfg.RedisConfig{
Host: "localhost",
Port: 6379,
Password: "",
Prefix: "test-prefix-semver",
}

prefixedClient, _ := redis.NewRedisClient(redisConfig, logging.NewLogger(&logging.LoggerOptions{}))
raw, _ := json.Marshal(*splitSemver)
prefixedClient.Set("SPLITIO.split.semver", raw, 0)
raw, _ = json.Marshal(*splitUnsupported)
prefixedClient.Set("SPLITIO.split.unsupported", raw, 0)

impTest := &ImpressionListenerTest{}
cfg := conf.Default()
cfg.LabelsEnabled = true
cfg.Advanced.ImpressionListener = impTest
cfg.ImpressionsMode = commonsCfg.ImpressionsModeOptimized
cfg.OperationMode = conf.RedisConsumer
cfg.Redis = *redisConfig

factory, _ := NewSplitFactory("test", cfg)
client := factory.Client()
client.BlockUntilReady(2)

// Calls treatments to generate one valid impression
time.Sleep(300 * time.Millisecond) // Let's wait until first call of recorders have finished
attributes := make(map[string]interface{})
attributes["version"] = "3.4.5"
evaluation := client.Treatment("user1", "semver", attributes)
if evaluation != "on" {
t.Error("evaluation for semver should be on")
}
evaluation = client.Treatment("user2", "unsupported", nil)
if evaluation != "control" {
t.Error("evaluation for unsupported should be control")
}
client.Destroy()

// Validate impressions
impressions, _ := prefixedClient.LRange("SPLITIO.impressions", 0, -1)

if len(impressions) != 2 {
t.Error("Impression length shold be 2")
}

for _, imp := range impressions {
var imprObject dtos.ImpressionQueueObject
_ = json.Unmarshal([]byte(imp), &imprObject)

if imprObject.Impression.KeyName == "user1" && imprObject.Impression.FeatureName == "semver" && imprObject.Impression.Pt != 0 {
t.Error("Pt should be 0.")
}
if imprObject.Impression.KeyName == "user2" && imprObject.Impression.FeatureName == "unsupported" && imprObject.Impression.Pt != 0 {
t.Error("Pt should be 0.")
}
}

// Clean redis
keys, _ := prefixedClient.Keys("SPLITIO*")
for _, k := range keys {
prefixedClient.Del(k)
}
}
2 changes: 1 addition & 1 deletion splitio/version.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package splitio

// Version contains a string with the split sdk version
const Version = "6.6.0-rc1"
const Version = "6.6.0-rc2"
Loading

0 comments on commit 6e3ad55

Please sign in to comment.