From 9e51b85330ad75256f46eeab729a2a898cbbbceb Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Thu, 7 Dec 2023 18:02:13 -0300 Subject: [PATCH 01/17] upgraded to commons v5 --- external/commons/mocks/evaluator.go | 7 +- external/commons/mocks/impmanager.go | 4 +- external/commons/mocks/imprecorder.go | 4 +- external/commons/mocks/splitstorage.go | 9 +- go.mod | 8 +- go.sum | 109 ++-------------------- splitio/commitsha.go | 2 +- splitio/link/client/types/interfaces.go | 2 +- splitio/link/client/v1/impl.go | 2 +- splitio/link/client/v1/impl_test.go | 2 +- splitio/link/service/v1/clientmgr_test.go | 2 +- splitio/sdk/conf/conf.go | 14 +-- splitio/sdk/helpers.go | 47 +++++----- splitio/sdk/helpers_test.go | 3 +- splitio/sdk/integration_test.go | 4 +- splitio/sdk/results.go | 2 +- splitio/sdk/sdk.go | 30 +++--- splitio/sdk/sdk_test.go | 10 +- splitio/sdk/storage/multi_test.go | 6 +- splitio/sdk/storage/storages.go | 2 +- splitio/sdk/validators.go | 2 +- splitio/sdk/workers/events.go | 14 +-- splitio/sdk/workers/events_test.go | 6 +- splitio/sdk/workers/impressions.go | 20 ++-- splitio/sdk/workers/impressions_test.go | 6 +- splitio/version.go | 2 +- 26 files changed, 119 insertions(+), 200 deletions(-) diff --git a/external/commons/mocks/evaluator.go b/external/commons/mocks/evaluator.go index 4fc386a..f4b8efc 100644 --- a/external/commons/mocks/evaluator.go +++ b/external/commons/mocks/evaluator.go @@ -1,7 +1,7 @@ package mocks import ( - "github.com/splitio/go-client/v6/splitio/engine/evaluator" + "github.com/splitio/go-split-commons/v5/engine/evaluator" "github.com/stretchr/testify/mock" ) @@ -21,4 +21,9 @@ func (e *EvaluatorMock) EvaluateFeatures(key string, bucketingKey *string, featu return args.Get(0).(evaluator.Results) } +func (e *EvaluatorMock) EvaluateFeatureByFlagSets(key string, bucketingKey *string, flagSets []string, attributes map[string]interface{}) evaluator.Results { + args := e.Called(key, bucketingKey, flagSets, attributes) + return args.Get(0).(evaluator.Results) +} + var _ evaluator.Interface = (*EvaluatorMock)(nil) diff --git a/external/commons/mocks/impmanager.go b/external/commons/mocks/impmanager.go index 59bba42..44b761f 100644 --- a/external/commons/mocks/impmanager.go +++ b/external/commons/mocks/impmanager.go @@ -1,8 +1,8 @@ package mocks import ( - "github.com/splitio/go-split-commons/v4/dtos" - "github.com/splitio/go-split-commons/v4/provisional" + "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/provisional" "github.com/stretchr/testify/mock" ) diff --git a/external/commons/mocks/imprecorder.go b/external/commons/mocks/imprecorder.go index 45d7bcd..8d498a7 100644 --- a/external/commons/mocks/imprecorder.go +++ b/external/commons/mocks/imprecorder.go @@ -1,8 +1,8 @@ package mocks import ( - "github.com/splitio/go-split-commons/v4/dtos" - "github.com/splitio/go-split-commons/v4/service" + "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/service" "github.com/stretchr/testify/mock" ) diff --git a/external/commons/mocks/splitstorage.go b/external/commons/mocks/splitstorage.go index 341f76c..e9c0c58 100644 --- a/external/commons/mocks/splitstorage.go +++ b/external/commons/mocks/splitstorage.go @@ -1,8 +1,8 @@ package mocks import ( - "github.com/splitio/go-split-commons/v4/dtos" - "github.com/splitio/go-split-commons/v4/storage" + "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/storage" "github.com/splitio/go-toolkit/v5/datastructures/set" "github.com/stretchr/testify/mock" ) @@ -58,4 +58,9 @@ func (m *SplitStorageMock) TrafficTypeExists(trafficType string) bool { return args.Bool(0) } +func (m *SplitStorageMock) GetNamesByFlagSets(sets []string) map[string][]string { + args := m.Called(sets) + return args.Get(0).(map[string][]string) +} + var _ storage.SplitStorage = (*SplitStorageMock)(nil) diff --git a/go.mod b/go.mod index 84fc0da..e6e8160 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,11 @@ module github.com/splitio/splitd go 1.20 require ( - github.com/splitio/go-client/v6 v6.2.1 - github.com/splitio/go-split-commons/v4 v4.2.3 - github.com/splitio/go-toolkit/v5 v5.2.2 + github.com/splitio/go-split-commons/v5 v5.1.0 + github.com/splitio/go-toolkit/v5 v5.3.2 github.com/stretchr/testify v1.8.1 github.com/vmihailenco/msgpack/v5 v5.3.5 - golang.org/x/sync v0.2.0 + golang.org/x/sync v0.3.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -17,4 +16,5 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect ) diff --git a/go.sum b/go.sum index c84ebd2..0f681e8 100644 --- a/go.sum +++ b/go.sum @@ -1,126 +1,33 @@ github.com/bits-and-blooms/bitset v1.3.1 h1:y+qrlmq3XsWi+xZqSaueaE8ry8Y127iMxlMfqcK8p0g= -github.com/bits-and-blooms/bitset v1.3.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= github.com/bits-and-blooms/bloom/v3 v3.3.1 h1:K2+A19bXT8gJR5mU7y+1yW6hsKfNCjcP2uNfLFKncjQ= -github.com/bits-and-blooms/bloom/v3 v3.3.1/go.mod h1:bhUUknWd5khVbTe4UgMCSiOOVJzr3tMoijSK3WwvW90= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= -github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= -github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= -github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/splitio/go-client/v6 v6.2.1 h1:EH3xYH7fr2c0I0ZtYvsyn7DjC9ZmoNAFLoKoT3BmQFU= -github.com/splitio/go-client/v6 v6.2.1/go.mod h1:+HnGMevmSUk56va2egs9W2s9mJ7LW9IXiDPB1ExOi+k= -github.com/splitio/go-split-commons/v4 v4.2.0/go.mod h1:mzanM00PV8t1FL6IHc2UXepIH2z79d49ArZ2LoJHGrY= -github.com/splitio/go-split-commons/v4 v4.2.3 h1:/bQg8Z0eCkF9RHl7Dh1SJ8j7Ci024bgtkZEWwEKXywc= -github.com/splitio/go-split-commons/v4 v4.2.3/go.mod h1:mzanM00PV8t1FL6IHc2UXepIH2z79d49ArZ2LoJHGrY= -github.com/splitio/go-toolkit/v5 v5.2.2 h1:VHSJoIH9tsRt2cCzGKN4WG3BoGCr0tCPZIl8APtJ4bw= -github.com/splitio/go-toolkit/v5 v5.2.2/go.mod h1:SYi/svhhtEgdMSb5tNcDcMjOSUH/7XVkvjp5dPL+nBE= +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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +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= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/splitio/commitsha.go b/splitio/commitsha.go index f4fb30e..84fea03 100644 --- a/splitio/commitsha.go +++ b/splitio/commitsha.go @@ -1,3 +1,3 @@ package splitio -const CommitSHA = "a41bede" +const CommitSHA = "ff4a059" diff --git a/splitio/link/client/types/interfaces.go b/splitio/link/client/types/interfaces.go index 50e1bc0..0a8d34f 100644 --- a/splitio/link/client/types/interfaces.go +++ b/splitio/link/client/types/interfaces.go @@ -1,7 +1,7 @@ package types import ( - "github.com/splitio/go-split-commons/v4/dtos" + "github.com/splitio/go-split-commons/v5/dtos" "github.com/splitio/splitd/splitio/sdk" ) diff --git a/splitio/link/client/v1/impl.go b/splitio/link/client/v1/impl.go index c361b4b..d8cdb70 100644 --- a/splitio/link/client/v1/impl.go +++ b/splitio/link/client/v1/impl.go @@ -3,7 +3,7 @@ package v1 import ( "fmt" - "github.com/splitio/go-split-commons/v4/dtos" + "github.com/splitio/go-split-commons/v5/dtos" "github.com/splitio/go-toolkit/v5/logging" "github.com/splitio/splitd/splitio" "github.com/splitio/splitd/splitio/link/client/types" diff --git a/splitio/link/client/v1/impl_test.go b/splitio/link/client/v1/impl_test.go index 8e4a637..5688f4d 100644 --- a/splitio/link/client/v1/impl_test.go +++ b/splitio/link/client/v1/impl_test.go @@ -3,7 +3,7 @@ package v1 import ( "testing" - "github.com/splitio/go-split-commons/v4/dtos" + "github.com/splitio/go-split-commons/v5/dtos" "github.com/splitio/go-toolkit/v5/logging" "github.com/splitio/splitd/splitio/common/lang" v1 "github.com/splitio/splitd/splitio/link/protocol/v1" diff --git a/splitio/link/service/v1/clientmgr_test.go b/splitio/link/service/v1/clientmgr_test.go index eadd5d5..2aed03f 100644 --- a/splitio/link/service/v1/clientmgr_test.go +++ b/splitio/link/service/v1/clientmgr_test.go @@ -5,7 +5,7 @@ import ( "io" "testing" - "github.com/splitio/go-split-commons/v4/dtos" + "github.com/splitio/go-split-commons/v5/dtos" "github.com/splitio/go-toolkit/v5/logging" "github.com/splitio/splitd/splitio/common/lang" "github.com/splitio/splitd/splitio/link/protocol" diff --git a/splitio/sdk/conf/conf.go b/splitio/sdk/conf/conf.go index 411fc30..1ad1045 100644 --- a/splitio/sdk/conf/conf.go +++ b/splitio/sdk/conf/conf.go @@ -3,7 +3,7 @@ package conf import ( "time" - "github.com/splitio/go-split-commons/v4/conf" + "github.com/splitio/go-split-commons/v5/conf" ) const ( @@ -19,6 +19,7 @@ type Config struct { Impressions Impressions Events Events URLs URLs + FlagSetsFilter []string } type Splits struct { @@ -66,6 +67,7 @@ func (c *Config) ToAdvancedConfig() *conf.AdvancedConfig { d.SegmentUpdateQueueSize = int64(c.Segments.UpdateBufferSize) d.SegmentWorkers = c.Segments.WorkerCount d.StreamingEnabled = c.StreamingEnabled + d.FlagSetsFilter = c.FlagSetsFilter d.AuthServiceURL = c.URLs.Auth d.SdkURL = c.URLs.SDK @@ -100,11 +102,11 @@ func DefaultConfig() *Config { CountSyncPeriod: 60 * time.Minute, PostConcurrency: 1, }, - Events: Events{ - QueueSize: 8192, - SyncPeriod: 1*time.Minute, - PostConcurrency: 1, - }, + Events: Events{ + QueueSize: 8192, + SyncPeriod: 1 * time.Minute, + PostConcurrency: 1, + }, URLs: URLs{ Auth: "https://auth.split.io", SDK: "https://sdk.split.io/api", diff --git a/splitio/sdk/helpers.go b/splitio/sdk/helpers.go index 17b2332..944b526 100644 --- a/splitio/sdk/helpers.go +++ b/splitio/sdk/helpers.go @@ -7,22 +7,21 @@ import ( sss "github.com/splitio/splitd/splitio/sdk/storage" "github.com/splitio/splitd/splitio/sdk/workers" - "github.com/splitio/go-split-commons/v4/conf" - "github.com/splitio/go-split-commons/v4/dtos" - "github.com/splitio/go-split-commons/v4/healthcheck/application" - "github.com/splitio/go-split-commons/v4/provisional" - "github.com/splitio/go-split-commons/v4/provisional/strategy" - "github.com/splitio/go-split-commons/v4/service/api" - "github.com/splitio/go-split-commons/v4/storage" - "github.com/splitio/go-split-commons/v4/storage/inmemory" - "github.com/splitio/go-split-commons/v4/storage/inmemory/mutexmap" - "github.com/splitio/go-split-commons/v4/synchronizer" - "github.com/splitio/go-split-commons/v4/synchronizer/worker/impressionscount" - "github.com/splitio/go-split-commons/v4/synchronizer/worker/segment" - "github.com/splitio/go-split-commons/v4/synchronizer/worker/split" - "github.com/splitio/go-split-commons/v4/tasks" - - storageCommon "github.com/splitio/go-split-commons/v4/storage" + "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" + "github.com/splitio/go-split-commons/v5/service/api" + "github.com/splitio/go-split-commons/v5/storage" + "github.com/splitio/go-split-commons/v5/storage/inmemory" + "github.com/splitio/go-split-commons/v5/storage/inmemory/mutexmap" + "github.com/splitio/go-split-commons/v5/synchronizer" + "github.com/splitio/go-split-commons/v5/synchronizer/worker/impressionscount" + "github.com/splitio/go-split-commons/v5/synchronizer/worker/segment" + "github.com/splitio/go-split-commons/v5/synchronizer/worker/split" + "github.com/splitio/go-split-commons/v5/tasks" "github.com/splitio/go-toolkit/v5/logging" ) @@ -32,11 +31,11 @@ func setupWorkers( str *storages, hc application.MonitorProducerInterface, cfg *sdkConf.Config, - + flagSetsFilter flagsets.FlagSetFilter, ) *synchronizer.Workers { return &synchronizer.Workers{ - SplitFetcher: split.NewSplitFetcher(str.splits, api.SplitFetcher, logger, str.telemetry, hc), - SegmentFetcher: segment.NewSegmentFetcher(str.splits, str.segments, api.SegmentFetcher, logger, str.telemetry, hc), + SplitUpdater: split.NewSplitUpdater(str.splits, api.SplitFetcher, logger, str.telemetry, hc, flagSetsFilter), + SegmentUpdater: segment.NewSegmentUpdater(str.splits, str.segments, api.SegmentFetcher, logger, str.telemetry, hc), ImpressionRecorder: workers.NewImpressionsWorker(logger, str.telemetry, api.ImpressionRecorder, str.impressions, &cfg.Impressions), EventRecorder: workers.NewEventsWorker(logger, str.telemetry, api.EventRecorder, str.events, &cfg.Events), } @@ -54,9 +53,9 @@ func setupTasks( impCfg := cfg.Impressions evCfg := cfg.Events tg := &synchronizer.SplitTasks{ - SplitSyncTask: tasks.NewFetchSplitsTask(workers.SplitFetcher, int(cfg.Splits.SyncPeriod.Seconds()), logger), + SplitSyncTask: tasks.NewFetchSplitsTask(workers.SplitUpdater, int(cfg.Splits.SyncPeriod.Seconds()), logger), SegmentSyncTask: tasks.NewFetchSegmentsTask( - workers.SegmentFetcher, + workers.SegmentUpdater, int(cfg.Segments.SyncPeriod.Seconds()), cfg.Segments.WorkerCount, cfg.Segments.QueueSize, @@ -86,7 +85,7 @@ type impComponents struct { counter *strategy.ImpressionsCounter } -func setupImpressionsComponents(c *sdkConf.Impressions, telemetry storageCommon.TelemetryRuntimeProducer) (impComponents, error) { +func setupImpressionsComponents(c *sdkConf.Impressions, telemetry storage.TelemetryRuntimeProducer) (impComponents, error) { observer, err := strategy.NewImpressionObserver(c.ObserverSize) if err != nil { @@ -118,13 +117,13 @@ type storages struct { events *sss.EventsStorage } -func setupStorages(cfg *sdkConf.Config) *storages { +func setupStorages(cfg *sdkConf.Config, flagSetsFilter flagsets.FlagSetFilter) *storages { ts, _ := inmemory.NewTelemetryStorage() iq, _ := sss.NewImpressionsQueue(cfg.Impressions.QueueSize) eq, _ := sss.NewEventsQueue(cfg.Events.QueueSize) return &storages{ - splits: mutexmap.NewMMSplitStorage(), + splits: mutexmap.NewMMSplitStorage(flagSetsFilter), segments: mutexmap.NewMMSegmentStorage(), impressions: iq, events: eq, diff --git a/splitio/sdk/helpers_test.go b/splitio/sdk/helpers_test.go index 8cf4441..bf34f09 100644 --- a/splitio/sdk/helpers_test.go +++ b/splitio/sdk/helpers_test.go @@ -3,6 +3,7 @@ package sdk import ( "testing" + "github.com/splitio/go-split-commons/v5/flagsets" sdkConf "github.com/splitio/splitd/splitio/sdk/conf" "github.com/stretchr/testify/assert" ) @@ -10,7 +11,7 @@ import ( func TestSetupImpressionsComponents(t *testing.T) { sdkCfg := sdkConf.DefaultConfig() - storages := setupStorages(sdkCfg) + storages := setupStorages(sdkCfg, flagsets.FlagSetFilter{}) ic, err := setupImpressionsComponents(&sdkCfg.Impressions, storages.telemetry) assert.Nil(t, err) diff --git a/splitio/sdk/integration_test.go b/splitio/sdk/integration_test.go index e6a3221..9aa6f69 100644 --- a/splitio/sdk/integration_test.go +++ b/splitio/sdk/integration_test.go @@ -10,7 +10,7 @@ import ( "sync/atomic" "testing" - "github.com/splitio/go-split-commons/v4/dtos" + "github.com/splitio/go-split-commons/v5/dtos" "github.com/splitio/go-toolkit/v5/logging" "github.com/splitio/splitd/splitio/sdk/conf" "github.com/splitio/splitd/splitio/sdk/types" @@ -103,7 +103,7 @@ func TestInstantiationAndGetTreatmentE2E(t *testing.T) { client, err := New(logger, "someApikey", sdkConf) assert.Nil(t, err) - res, err := client.Treatment(&types.ClientConfig{}, "aaaaaaklmnbv", nil, "split", nil) + res, _ := client.Treatment(&types.ClientConfig{}, "aaaaaaklmnbv", nil, "split", nil) assert.Equal(t, "on", res.Treatment) assert.Nil(t, client.Shutdown()) diff --git a/splitio/sdk/results.go b/splitio/sdk/results.go index 360f0bf..9c73acd 100644 --- a/splitio/sdk/results.go +++ b/splitio/sdk/results.go @@ -1,6 +1,6 @@ package sdk -import "github.com/splitio/go-split-commons/v4/dtos" +import "github.com/splitio/go-split-commons/v5/dtos" type EvaluationResult struct { Treatment string diff --git a/splitio/sdk/sdk.go b/splitio/sdk/sdk.go index 8df5a74..da0d008 100644 --- a/splitio/sdk/sdk.go +++ b/splitio/sdk/sdk.go @@ -6,19 +6,18 @@ import ( "time" "github.com/splitio/splitd/splitio/sdk/conf" - sdkConf "github.com/splitio/splitd/splitio/sdk/conf" "github.com/splitio/splitd/splitio/sdk/storage" "github.com/splitio/splitd/splitio/sdk/types" - "github.com/splitio/go-client/v6/splitio/engine" - "github.com/splitio/go-client/v6/splitio/engine/evaluator" - - "github.com/splitio/go-split-commons/v4/dtos" - "github.com/splitio/go-split-commons/v4/healthcheck/application" - "github.com/splitio/go-split-commons/v4/provisional" - "github.com/splitio/go-split-commons/v4/service/api" - commonStorage "github.com/splitio/go-split-commons/v4/storage" - "github.com/splitio/go-split-commons/v4/synchronizer" + "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/service/api" + commonStorage "github.com/splitio/go-split-commons/v5/storage" + "github.com/splitio/go-split-commons/v5/synchronizer" "github.com/splitio/go-toolkit/v5/common" "github.com/splitio/go-toolkit/v5/logging" "github.com/splitio/splitd/splitio" @@ -55,8 +54,7 @@ type Impl struct { es *storage.EventsStorage iq provisional.ImpressionManager splitStorage commonStorage.SplitStorage - cfg sdkConf.Config - status chan int + cfg conf.Config queueFullChan chan string validator Validator } @@ -72,7 +70,9 @@ func New(logger logging.LoggerInterface, apikey string, c *conf.Config) (*Impl, md := dtos.Metadata{SDKVersion: fmt.Sprintf("splitd-%s", splitio.Version)} advCfg := c.ToAdvancedConfig() - stores := setupStorages(c) + flagSetsFilter := flagsets.NewFlagSetFilter(advCfg.FlagSetsFilter) + + stores := setupStorages(c, flagSetsFilter) impc, err := setupImpressionsComponents(&c.Impressions, stores.telemetry) if err != nil { return nil, fmt.Errorf("error setting up impressions components") @@ -82,9 +82,9 @@ func New(logger logging.LoggerInterface, apikey string, c *conf.Config) (*Impl, queueFullChan := make(chan string, 2) splitApi := api.NewSplitAPI(apikey, *advCfg, logger, md) - workers := setupWorkers(logger, splitApi, stores, hc, c) + workers := setupWorkers(logger, splitApi, stores, hc, c, flagSetsFilter) tasks := setupTasks(c, stores, logger, workers, impc, md, splitApi) - sync := synchronizer.NewSynchronizer(*advCfg, *tasks, *workers, logger, queueFullChan, nil) + sync := synchronizer.NewSynchronizer(*advCfg, *tasks, *workers, logger, queueFullChan) status := make(chan int, 10) manager, err := synchronizer.NewSynchronizerManager(sync, logger, *advCfg, splitApi.AuthClient, stores.splits, status, stores.telemetry, md, nil, hc) diff --git a/splitio/sdk/sdk_test.go b/splitio/sdk/sdk_test.go index eb0fe87..5b7c882 100644 --- a/splitio/sdk/sdk_test.go +++ b/splitio/sdk/sdk_test.go @@ -6,10 +6,10 @@ import ( "testing" "time" - "github.com/splitio/go-client/v6/splitio/engine/evaluator" - "github.com/splitio/go-split-commons/v4/dtos" - "github.com/splitio/go-split-commons/v4/storage/inmemory" - "github.com/splitio/go-split-commons/v4/synchronizer" + "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/engine/evaluator" + "github.com/splitio/go-split-commons/v5/storage/inmemory" + "github.com/splitio/go-split-commons/v5/synchronizer" "github.com/splitio/go-toolkit/v5/logging" "github.com/splitio/splitd/external/commons/mocks" "github.com/splitio/splitd/splitio/common/lang" @@ -221,7 +221,7 @@ func TestImpressionsQueueFull(t *testing.T) { ts, _ := inmemory.NewTelemetryStorage() iw := workers.NewImpressionsWorker(logger, ts, impRecorder, is, &conf.Impressions{Mode: "optimized", SyncPeriod: 100 * time.Second}) sworkers := synchronizer.Workers{ImpressionRecorder: iw} - sy := synchronizer.NewSynchronizer(*conf.DefaultConfig().ToAdvancedConfig(), synchronizer.SplitTasks{}, sworkers, logger, queueFullChan, nil) + sy := synchronizer.NewSynchronizer(*conf.DefaultConfig().ToAdvancedConfig(), synchronizer.SplitTasks{}, sworkers, logger, queueFullChan) sy.StartPeriodicDataRecording() // @} diff --git a/splitio/sdk/storage/multi_test.go b/splitio/sdk/storage/multi_test.go index aa361bf..e0ab5a9 100644 --- a/splitio/sdk/storage/multi_test.go +++ b/splitio/sdk/storage/multi_test.go @@ -3,7 +3,7 @@ package storage import ( "testing" - "github.com/splitio/go-split-commons/v4/dtos" + "github.com/splitio/go-split-commons/v5/dtos" "github.com/splitio/splitd/splitio/sdk/types" "github.com/stretchr/testify/assert" @@ -34,7 +34,7 @@ func TestMultiStorageBasic(t *testing.T) { assert.Equal(t, ErrQueueEmpty, err) assert.Equal(t, 4, n) case "php-1.2.3": - // do nothing, to be used in the next assertions + // do nothing, to be used in the next assertions default: assert.Fail(t, "unexpected metadata: "+cm.SdkVersion) } @@ -43,7 +43,7 @@ func TestMultiStorageBasic(t *testing.T) { mq.RangeAndClear(func(cm types.ClientMetadata, q *LockingQueue[dtos.EventDTO]) { switch cm.SdkVersion { case "go-1.2.3": - // used previously + // used previously case "php-1.2.3": assert.Equal(t, 3, q.Len()) var buf []dtos.EventDTO diff --git a/splitio/sdk/storage/storages.go b/splitio/sdk/storage/storages.go index 082d599..85b3c07 100644 --- a/splitio/sdk/storage/storages.go +++ b/splitio/sdk/storage/storages.go @@ -3,7 +3,7 @@ package storage import ( "math" - "github.com/splitio/go-split-commons/v4/dtos" + "github.com/splitio/go-split-commons/v5/dtos" "github.com/splitio/splitd/splitio/sdk/types" ) diff --git a/splitio/sdk/validators.go b/splitio/sdk/validators.go index 529343f..dfb7399 100644 --- a/splitio/sdk/validators.go +++ b/splitio/sdk/validators.go @@ -4,7 +4,7 @@ import ( "errors" "strings" - "github.com/splitio/go-split-commons/v4/storage" + "github.com/splitio/go-split-commons/v5/storage" "github.com/splitio/go-toolkit/v5/logging" ) diff --git a/splitio/sdk/workers/events.go b/splitio/sdk/workers/events.go index d5c95b0..96e1dcb 100644 --- a/splitio/sdk/workers/events.go +++ b/splitio/sdk/workers/events.go @@ -9,10 +9,10 @@ import ( "github.com/splitio/splitd/splitio/sdk/types" serrors "github.com/splitio/splitd/splitio/util/errors" - "github.com/splitio/go-split-commons/v4/dtos" - "github.com/splitio/go-split-commons/v4/service" - "github.com/splitio/go-split-commons/v4/storage" - "github.com/splitio/go-split-commons/v4/synchronizer/worker/event" + "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/service" + "github.com/splitio/go-split-commons/v5/storage" + "github.com/splitio/go-split-commons/v5/synchronizer/worker/event" "github.com/splitio/go-toolkit/v5/logging" gtsync "github.com/splitio/go-toolkit/v5/sync" ) @@ -57,9 +57,9 @@ func (m *MultiMetaEventsWorker) FlushEvents(bulkSize int64) error { var errs serrors.ConcurrentErrorCollector var wg sync.WaitGroup - // same logic as impressions workers, without the need for formatting. check impressions.go for a better - // description of what's being done - if err := m.iq.RangeAndClear(func(md types.ClientMetadata, q *sss.LockingQueue[dtos.EventDTO]) { + // same logic as impressions workers, without the need for formatting. check impressions.go for a better + // description of what's being done + if err := m.iq.RangeAndClear(func(md types.ClientMetadata, q *sss.LockingQueue[dtos.EventDTO]) { extracted := make([]dtos.EventDTO, 0, q.Len()) n, err := q.Pop(q.Len(), &extracted) if err != nil && !errors.Is(err, sss.ErrQueueEmpty) { diff --git a/splitio/sdk/workers/events_test.go b/splitio/sdk/workers/events_test.go index 3bc83ea..e52c87b 100644 --- a/splitio/sdk/workers/events_test.go +++ b/splitio/sdk/workers/events_test.go @@ -4,9 +4,9 @@ import ( "testing" "time" - "github.com/splitio/go-split-commons/v4/dtos" - "github.com/splitio/go-split-commons/v4/service" - "github.com/splitio/go-split-commons/v4/storage/inmemory" + "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/service" + "github.com/splitio/go-split-commons/v5/storage/inmemory" "github.com/splitio/go-toolkit/v5/logging" "github.com/splitio/splitd/splitio/sdk/conf" sss "github.com/splitio/splitd/splitio/sdk/storage" diff --git a/splitio/sdk/workers/impressions.go b/splitio/sdk/workers/impressions.go index 6b97f73..65c3438 100644 --- a/splitio/sdk/workers/impressions.go +++ b/splitio/sdk/workers/impressions.go @@ -9,10 +9,10 @@ import ( "github.com/splitio/splitd/splitio/sdk/types" serrors "github.com/splitio/splitd/splitio/util/errors" - "github.com/splitio/go-split-commons/v4/dtos" - "github.com/splitio/go-split-commons/v4/service" - "github.com/splitio/go-split-commons/v4/storage" - "github.com/splitio/go-split-commons/v4/synchronizer/worker/impression" + "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/service" + "github.com/splitio/go-split-commons/v5/storage" + "github.com/splitio/go-split-commons/v5/synchronizer/worker/impression" "github.com/splitio/go-toolkit/v5/logging" gtsync "github.com/splitio/go-toolkit/v5/sync" ) @@ -47,20 +47,20 @@ func NewImpressionsWorker( func (m *MultiMetaImpressionWorker) FlushImpressions(bulkSize int64) error { // prevent 2 evictions from happening at the same time. we don't want a sync.Mutex since that would only cause 43928729 - // function calls to pile up and get called after each mutex release. + // function calls to pile up and get called after each mutex release. if !m.runnning.TestAndSet() { m.logger.Warning("flush/sync requested while another one is in progress. ignoring") return nil } defer m.runnning.Unset() - var errs serrors.ConcurrentErrorCollector + var errs serrors.ConcurrentErrorCollector var wg sync.WaitGroup // iterate all internal queues (one per thin-client associate-data) - // for each [metadata, impressions] tuple, format impressions accordingly, and create a goroutine to post them in BG. - // after all impressions posting-goroutines have been created, wait for all of them to complete, collect errors, - // and unset the `running` flag so that this func can be called again + // for each [metadata, impressions] tuple, format impressions accordingly, and create a goroutine to post them in BG. + // after all impressions posting-goroutines have been created, wait for all of them to complete, collect errors, + // and unset the `running` flag so that this func can be called again if err := m.iq.RangeAndClear(func(md types.ClientMetadata, q *sss.LockingQueue[dtos.Impression]) { extracted := make([]dtos.Impression, 0, q.Len()) n, err := q.Pop(q.Len(), &extracted) @@ -79,7 +79,7 @@ func (m *MultiMetaImpressionWorker) FlushImpressions(bulkSize int64) error { go func(imps []dtos.ImpressionsDTO, md dtos.Metadata) { defer wg.Done() if err := m.llrec.Record(imps, md, nil); err != nil { - errs.Append(err) + errs.Append(err) } }(formatted, dtos.Metadata{SDKVersion: md.SdkVersion}) }); err != nil { diff --git a/splitio/sdk/workers/impressions_test.go b/splitio/sdk/workers/impressions_test.go index 1285ddf..0e57f69 100644 --- a/splitio/sdk/workers/impressions_test.go +++ b/splitio/sdk/workers/impressions_test.go @@ -6,9 +6,9 @@ import ( "testing" "time" - "github.com/splitio/go-split-commons/v4/dtos" - "github.com/splitio/go-split-commons/v4/service" - "github.com/splitio/go-split-commons/v4/storage/inmemory" + "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/service" + "github.com/splitio/go-split-commons/v5/storage/inmemory" "github.com/splitio/go-toolkit/v5/logging" "github.com/splitio/splitd/splitio/sdk/conf" sss "github.com/splitio/splitd/splitio/sdk/storage" diff --git a/splitio/version.go b/splitio/version.go index ccae879..14a44ce 100644 --- a/splitio/version.go +++ b/splitio/version.go @@ -1,3 +1,3 @@ package splitio -const Version = "1.1.1" +const Version = "1.2.0-rc1" From 641b3d52758a43125d14bde1a068c6268afbb1cb Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Mon, 18 Dec 2023 14:37:45 -0300 Subject: [PATCH 02/17] added TreatmentsByFlagSet logic --- splitio/commitsha.go | 2 +- splitio/link/protocol/v1/responses.go | 7 ++- splitio/link/protocol/v1/rpcs.go | 68 +++++++++++++++++++++-- splitio/link/service/v1/clientmgr.go | 45 ++++++++++++++++ splitio/sdk/mocks/sdk.go | 12 +++++ splitio/sdk/sdk.go | 17 ++++++ splitio/sdk/sdk_test.go | 77 +++++++++++++++++++++++++++ 7 files changed, 222 insertions(+), 6 deletions(-) diff --git a/splitio/commitsha.go b/splitio/commitsha.go index 84fea03..296bc16 100644 --- a/splitio/commitsha.go +++ b/splitio/commitsha.go @@ -1,3 +1,3 @@ package splitio -const CommitSHA = "ff4a059" +const CommitSHA = "9e51b85" diff --git a/splitio/link/protocol/v1/responses.go b/splitio/link/protocol/v1/responses.go index 2f66d75..90ce93a 100644 --- a/splitio/link/protocol/v1/responses.go +++ b/splitio/link/protocol/v1/responses.go @@ -14,6 +14,10 @@ type ResponseWrapper[T validPayloadsConstraint] struct { type RegisterPayload struct{} +type TreatmentsWithFeaturePayload struct { + Results map[string]TreatmentPayload `msgpack:"r"` +} + type TreatmentPayload struct { Treatment string `msgpack:"t"` Config *string `msgpack:"c,omitempty"` @@ -58,5 +62,6 @@ type validPayloadsConstraint interface { SplitNamesPayload | SplitPayload | SplitsPayload | - RegisterPayload + RegisterPayload | + TreatmentsWithFeaturePayload } diff --git a/splitio/link/protocol/v1/rpcs.go b/splitio/link/protocol/v1/rpcs.go index 9c117e8..379593b 100644 --- a/splitio/link/protocol/v1/rpcs.go +++ b/splitio/link/protocol/v1/rpcs.go @@ -14,10 +14,12 @@ const ( OCRegister OpCode = 0x00 // Treatment-related ops - OCTreatment OpCode = 0x11 - OCTreatments OpCode = 0x12 - OCTreatmentWithConfig OpCode = 0x13 - OCTreatmentsWithConfig OpCode = 0x14 + OCTreatment OpCode = 0x11 + OCTreatments OpCode = 0x12 + OCTreatmentWithConfig OpCode = 0x13 + OCTreatmentsWithConfig OpCode = 0x14 + OCTreatmentsByFlagSet OpCode = 0x15 + OCTreatmentsWithConfigByFlagSet OpCode = 0x16 // Track-related ops OCTrack OpCode = 0x80 @@ -39,6 +41,10 @@ func (o OpCode) String() string { return "treatment-with-config" case OCTreatmentsWithConfig: return "treatments-with-config" + case OCTreatmentsByFlagSet: + return "treatments-by-flag=set" + case OCTreatmentsWithConfigByFlagSet: + return "treatments-with-config-by-flag=set" case OCTrack: return "track" case OCSplitNames: @@ -229,6 +235,60 @@ func (t *TreatmentsArgs) PopulateFromRPC(rpc *RPC) error { return nil } +const ( + TreatmentsByFlagSetArgKeyIdx int = 0 + TreatmentsByFlagSetArgBucketingKeyIdx int = 1 + TreatmentsByFlagSetArgFlagSetIdx int = 2 + TreatmentsByFlagSetArgAttributesIdx int = 3 +) + +type TreatmentsByFlagSetArgs struct { + Key string `msgpack:"k"` + BucketingKey *string `msgpack:"b"` + FlagSet string `msgpack:"f"` + Attributes map[string]interface{} `msgpack:"a"` +} + +func (r TreatmentsByFlagSetArgs) Encode() []interface{} { + var bk string + if r.BucketingKey != nil { + bk = *r.BucketingKey + } + return []interface{}{r.Key, bk, r.FlagSet, r.Attributes} +} + +func (t *TreatmentsByFlagSetArgs) PopulateFromRPC(rpc *RPC) error { + if rpc.OpCode != OCTreatmentsByFlagSet && rpc.OpCode != OCTreatmentsWithConfigByFlagSet { + return RPCParseError{Code: PECOpCodeMismatch} + } + if len(rpc.Args) != 4 { + return RPCParseError{Code: PECWrongArgCount} + } + + var ok bool + var err error + + if t.Key, ok = rpc.Args[TreatmentsByFlagSetArgKeyIdx].(string); !ok { + return RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsArgKeyIdx)} + } + + if t.BucketingKey, err = getOptionalRef[string](rpc.Args[TreatmentsByFlagSetArgBucketingKeyIdx]); err != nil { + return RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsArgBucketingKeyIdx)} + } + + if t.FlagSet, ok = rpc.Args[TreatmentsByFlagSetArgFlagSetIdx].(string); !ok { + return RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetArgFlagSetIdx)} + } + + rawAttrs, err := getOptional[map[string]interface{}](rpc.Args[TreatmentsByFlagSetArgAttributesIdx]) + if err != nil { + return RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetArgAttributesIdx)} + } + t.Attributes = sanitizeAttributes(rawAttrs) + + return nil +} + const ( TrackArgKeyIdx int = 0 TrackArgTrafficTypeIdx int = 1 diff --git a/splitio/link/service/v1/clientmgr.go b/splitio/link/service/v1/clientmgr.go index d61c711..ef2d9b2 100644 --- a/splitio/link/service/v1/clientmgr.go +++ b/splitio/link/service/v1/clientmgr.go @@ -124,6 +124,10 @@ func (m *ClientManager) dispatchRPC(rpc *protov1.RPC) (interface{}, error) { return m.handleGetTreatment(rpc, true) case protov1.OCTreatmentsWithConfig: return m.handleGetTreatments(rpc, true) + case protov1.OCTreatmentsByFlagSet: + return m.handleGetTreatmentsByFlagSet(rpc, false) + case protov1.OCTreatmentsWithConfigByFlagSet: + return m.handleGetTreatmentsByFlagSet(rpc, true) case protov1.OCTrack: return m.handleTrack(rpc) case protov1.OCSplitNames: @@ -228,6 +232,47 @@ func (m *ClientManager) handleGetTreatments(rpc *protov1.RPC, withConfig bool) ( return response, nil } +func (m *ClientManager) handleGetTreatmentsByFlagSet(rpc *protov1.RPC, withConfig bool) (interface{}, error) { + + var args protov1.TreatmentsByFlagSetArgs + if err := args.PopulateFromRPC(rpc); err != nil { + return nil, fmt.Errorf("error parsing treatments arguments: %w", err) + } + + res, err := m.splitSDK.TreatmentsByFlagSet(m.clientConfig, args.Key, args.BucketingKey, args.FlagSet, args.Attributes) + if err != nil { + return &protov1.ResponseWrapper[protov1.TreatmentsWithFeaturePayload]{Status: protov1.ResultInternalError}, err + } + + results := make(map[string]protov1.TreatmentPayload, 0) + for feature, evaluationResult := range res { + currentPayload := protov1.TreatmentPayload{ + Treatment: evaluationResult.Treatment, + } + + if m.clientConfig.ReturnImpressionData && evaluationResult.Impression != nil { + currentPayload.ListenerData = &protov1.ListenerExtraData{ + Label: evaluationResult.Impression.Label, + Timestamp: evaluationResult.Impression.Time, + ChangeNumber: evaluationResult.Impression.ChangeNumber, + } + } + + if withConfig { + currentPayload.Config = evaluationResult.Config + } + + results[feature] = currentPayload + } + + response := &protov1.ResponseWrapper[protov1.TreatmentsWithFeaturePayload]{ + Status: protov1.ResultOk, + Payload: protov1.TreatmentsWithFeaturePayload{Results: results}, + } + + return response, nil +} + func (m *ClientManager) handleTrack(rpc *protov1.RPC) (interface{}, error) { var args protov1.TrackArgs diff --git a/splitio/sdk/mocks/sdk.go b/splitio/sdk/mocks/sdk.go index 9fa5e6d..52328bf 100644 --- a/splitio/sdk/mocks/sdk.go +++ b/splitio/sdk/mocks/sdk.go @@ -34,6 +34,18 @@ func (m *SDKMock) Treatments( return args.Get(0).(map[string]sdk.EvaluationResult), args.Error(1) } +// TreatmentsByFlagSet implements sdk.Interface +func (m *SDKMock) TreatmentsByFlagSet( + md *types.ClientConfig, + key string, + bucketingKey *string, + flagSet string, + attributes map[string]interface{}, +) (map[string]sdk.EvaluationResult, error) { + args := m.Called(md, key, bucketingKey, flagSet, attributes) + return args.Get(0).(map[string]sdk.EvaluationResult), args.Error(1) +} + // Track implements sdk.Interface func (m *SDKMock) Track(cfg *types.ClientConfig, key string, trafficType string, eventType string, value *float64, properties map[string]interface{}) error { args := m.Called(cfg, key, trafficType, eventType, value, properties) diff --git a/splitio/sdk/sdk.go b/splitio/sdk/sdk.go index da0d008..8f0652b 100644 --- a/splitio/sdk/sdk.go +++ b/splitio/sdk/sdk.go @@ -38,6 +38,7 @@ type Attributes = map[string]interface{} type Interface interface { Treatment(cfg *types.ClientConfig, key string, bucketingKey *string, feature string, attributes map[string]interface{}) (*EvaluationResult, error) Treatments(cfg *types.ClientConfig, key string, bucketingKey *string, features []string, attributes map[string]interface{}) (map[string]EvaluationResult, error) + TreatmentsByFlagSet(cfg *types.ClientConfig, key string, bucketingKey *string, flagSet string, attributes map[string]interface{}) (map[string]EvaluationResult, error) Track(cfg *types.ClientConfig, key string, trafficType string, eventType string, value *float64, properties map[string]interface{}) error SplitNames() ([]string, error) Splits() ([]SplitView, error) @@ -152,6 +153,22 @@ func (i *Impl) Treatments(cfg *types.ClientConfig, key string, bk *string, featu return toRet, nil } +// TreatmentsByFlagSet implements Interface +func (i *Impl) TreatmentsByFlagSet(cfg *types.ClientConfig, key string, bk *string, flagSet string, attributes Attributes) (map[string]EvaluationResult, error) { + + res := i.ev.EvaluateFeatureByFlagSets(key, bk, []string{flagSet}, attributes) + toRet := make(map[string]EvaluationResult, len(res.Evaluations)) + for feature, curr := range res.Evaluations { + var eres EvaluationResult + eres.Treatment = curr.Treatment + eres.Impression = i.handleImpression(key, bk, feature, &curr, cfg.Metadata) + eres.Config = curr.Config + toRet[feature] = eres + } + + return toRet, nil +} + func (i *Impl) Track(cfg *types.ClientConfig, key string, trafficType string, eventType string, value *float64, properties map[string]interface{}) error { // TODO(mredolatti): validate traffic type & truncate properties if needed diff --git a/splitio/sdk/sdk_test.go b/splitio/sdk/sdk_test.go index 5b7c882..3ba3726 100644 --- a/splitio/sdk/sdk_test.go +++ b/splitio/sdk/sdk_test.go @@ -206,6 +206,83 @@ func TestTreatments(t *testing.T) { } +func TestTreatmentsByFlagSet(t *testing.T) { + is, _ := storage.NewImpressionsQueue(100) + + ev := &mocks.EvaluatorMock{} + ev.On("EvaluateFeatureByFlagSets", "key1", (*string)(nil), []string{"set"}, Attributes{"a": 1}). + Return(evaluator.Results{Evaluations: map[string]evaluator.Result{ + "f1": {Treatment: "on", Label: "label1", EvaluationTime: 1 * time.Millisecond, SplitChangeNumber: 123}, + "f2": {Treatment: "on", Label: "label2", EvaluationTime: 2 * time.Millisecond, SplitChangeNumber: 124}, + "f3": {Treatment: "on", Label: "label3", EvaluationTime: 3 * time.Millisecond, SplitChangeNumber: 125}, + }}). + Once() + + expectedImpressions := []dtos.Impression{ + {KeyName: "key1", BucketingKey: "", FeatureName: "f1", Treatment: "on", Label: "label1", ChangeNumber: 123}, + {KeyName: "key1", BucketingKey: "", FeatureName: "f2", Treatment: "on", Label: "label2", ChangeNumber: 124}, + {KeyName: "key1", BucketingKey: "", FeatureName: "f3", Treatment: "on", Label: "label3", ChangeNumber: 125}, + } + im := &mocks.ImpressionManagerMock{} + im.On("ProcessSingle", mock.Anything). + Run(func(args mock.Arguments) { + assertImpEq(t, &expectedImpressions[0], args.Get(0).(*dtos.Impression)) + }). + Return(true). + Once() + im.On("ProcessSingle", mock.Anything). + Run(func(args mock.Arguments) { + assertImpEq(t, &expectedImpressions[1], args.Get(0).(*dtos.Impression)) + }). + Return(true). + Once() + im.On("ProcessSingle", mock.Anything). + Run(func(args mock.Arguments) { + assertImpEq(t, &expectedImpressions[2], args.Get(0).(*dtos.Impression)) + }). + Return(true). + Once() + + client := &Impl{ + logger: logging.NewLogger(nil), + is: is, + ev: ev, + iq: im, + cfg: conf.Config{LabelsEnabled: true}, + } + + res, err := client.TreatmentsByFlagSet( + &types.ClientConfig{Metadata: types.ClientMetadata{ID: "some", SdkVersion: "go-1.2.3"}}, + "key1", nil, "set", Attributes{"a": 1}) + assert.Nil(t, err) + assert.Nil(t, res["f1"].Config) + assert.Nil(t, res["f2"].Config) + assert.Nil(t, res["f3"].Config) + assertImpEq(t, &expectedImpressions[0], res["f1"].Impression) + assertImpEq(t, &expectedImpressions[1], res["f2"].Impression) + assertImpEq(t, &expectedImpressions[2], res["f3"].Impression) + + err = is.RangeAndClear(func(md types.ClientMetadata, st *storage.LockingQueue[dtos.Impression]) { + assert.Equal(t, types.ClientMetadata{ID: "some", SdkVersion: "go-1.2.3"}, md) + assert.Equal(t, 3, st.Len()) + + var imps []dtos.Impression + n, err := st.Pop(3, &imps) + assert.Nil(t, nil) + assert.Equal(t, 3, n) + assert.Equal(t, 3, len(imps)) + assertImpEq(t, &expectedImpressions[0], &imps[0]) + assertImpEq(t, &expectedImpressions[1], &imps[1]) + assertImpEq(t, &expectedImpressions[2], &imps[2]) + n, err = st.Pop(1, &imps) + assert.Equal(t, 0, n) + assert.ErrorIs(t, err, storage.ErrQueueEmpty) + + }) + assert.Nil(t, err) + +} + func TestImpressionsQueueFull(t *testing.T) { logger := logging.NewLogger(nil) From b98165e0a994b5049a9c35176dfe082502dc7247 Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Thu, 21 Dec 2023 14:42:18 -0300 Subject: [PATCH 03/17] fixed naming --- splitio/link/protocol/v1/rpcs.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/splitio/link/protocol/v1/rpcs.go b/splitio/link/protocol/v1/rpcs.go index 379593b..720d53a 100644 --- a/splitio/link/protocol/v1/rpcs.go +++ b/splitio/link/protocol/v1/rpcs.go @@ -42,9 +42,9 @@ func (o OpCode) String() string { case OCTreatmentsWithConfig: return "treatments-with-config" case OCTreatmentsByFlagSet: - return "treatments-by-flag=set" + return "treatments-by-flag-set" case OCTreatmentsWithConfigByFlagSet: - return "treatments-with-config-by-flag=set" + return "treatments-with-config-by-flag-set" case OCTrack: return "track" case OCSplitNames: @@ -269,11 +269,11 @@ func (t *TreatmentsByFlagSetArgs) PopulateFromRPC(rpc *RPC) error { var err error if t.Key, ok = rpc.Args[TreatmentsByFlagSetArgKeyIdx].(string); !ok { - return RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsArgKeyIdx)} + return RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetArgKeyIdx)} } if t.BucketingKey, err = getOptionalRef[string](rpc.Args[TreatmentsByFlagSetArgBucketingKeyIdx]); err != nil { - return RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsArgBucketingKeyIdx)} + return RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetArgBucketingKeyIdx)} } if t.FlagSet, ok = rpc.Args[TreatmentsByFlagSetArgFlagSetIdx].(string); !ok { From 6f6fc38b3d84aecf0de93b811c5ba9fc2c301a8c Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Tue, 2 Jan 2024 12:06:04 -0300 Subject: [PATCH 04/17] added treatmentsbyflagsets --- splitio/commitsha.go | 2 +- splitio/link/protocol/v1/rpcs.go | 88 ++++++++++++++++++++++++---- splitio/link/service/v1/clientmgr.go | 45 ++++++++++++++ splitio/sdk/mocks/sdk.go | 12 ++++ splitio/sdk/sdk.go | 17 ++++++ splitio/sdk/sdk_test.go | 77 ++++++++++++++++++++++++ 6 files changed, 229 insertions(+), 12 deletions(-) diff --git a/splitio/commitsha.go b/splitio/commitsha.go index 296bc16..51dcc58 100644 --- a/splitio/commitsha.go +++ b/splitio/commitsha.go @@ -1,3 +1,3 @@ package splitio -const CommitSHA = "9e51b85" +const CommitSHA = "b98165e" diff --git a/splitio/link/protocol/v1/rpcs.go b/splitio/link/protocol/v1/rpcs.go index 720d53a..6cc1477 100644 --- a/splitio/link/protocol/v1/rpcs.go +++ b/splitio/link/protocol/v1/rpcs.go @@ -14,12 +14,14 @@ const ( OCRegister OpCode = 0x00 // Treatment-related ops - OCTreatment OpCode = 0x11 - OCTreatments OpCode = 0x12 - OCTreatmentWithConfig OpCode = 0x13 - OCTreatmentsWithConfig OpCode = 0x14 - OCTreatmentsByFlagSet OpCode = 0x15 - OCTreatmentsWithConfigByFlagSet OpCode = 0x16 + OCTreatment OpCode = 0x11 + OCTreatments OpCode = 0x12 + OCTreatmentWithConfig OpCode = 0x13 + OCTreatmentsWithConfig OpCode = 0x14 + OCTreatmentsByFlagSet OpCode = 0x15 + OCTreatmentsWithConfigByFlagSet OpCode = 0x16 + OCTreatmentsByFlagSets OpCode = 0x17 + OCTreatmentsWithConfigByFlagSets OpCode = 0x18 // Track-related ops OCTrack OpCode = 0x80 @@ -45,6 +47,10 @@ func (o OpCode) String() string { return "treatments-by-flag-set" case OCTreatmentsWithConfigByFlagSet: return "treatments-with-config-by-flag-set" + case OCTreatmentsByFlagSets: + return "treatments-by-flag-sets" + case OCTreatmentsWithConfigByFlagSets: + return "treatments-with-config-by-flag-sets" case OCTrack: return "track" case OCSplitNames: @@ -221,7 +227,7 @@ func (t *TreatmentsArgs) PopulateFromRPC(rpc *RPC) error { return RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsArgFeaturesIdx)} } - t.Features, ok = sanitizeFeatureList(rawFeatureList) + t.Features, ok = sanitizeToStringSlice(rawFeatureList) if !ok { return RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsArgFeaturesIdx)} } @@ -289,6 +295,66 @@ func (t *TreatmentsByFlagSetArgs) PopulateFromRPC(rpc *RPC) error { return nil } +const ( + TreatmentsByFlagSetsArgKeyIdx int = 0 + TreatmentsByFlagSetsArgBucketingKeyIdx int = 1 + TreatmentsByFlagSetsArgFlagSetsIdx int = 2 + TreatmentsByFlagSetsArgAttributesIdx int = 3 +) + +type TreatmentsByFlagSetsArgs struct { + Key string `msgpack:"k"` + BucketingKey *string `msgpack:"b"` + FlagSets []string `msgpack:"f"` + Attributes map[string]interface{} `msgpack:"a"` +} + +func (r TreatmentsByFlagSetsArgs) Encode() []interface{} { + var bk string + if r.BucketingKey != nil { + bk = *r.BucketingKey + } + return []interface{}{r.Key, bk, r.FlagSets, r.Attributes} +} + +func (t *TreatmentsByFlagSetsArgs) PopulateFromRPC(rpc *RPC) error { + if rpc.OpCode != OCTreatmentsByFlagSets && rpc.OpCode != OCTreatmentsWithConfigByFlagSets { + return RPCParseError{Code: PECOpCodeMismatch} + } + if len(rpc.Args) != 4 { + return RPCParseError{Code: PECWrongArgCount} + } + + var ok bool + var err error + + if t.Key, ok = rpc.Args[TreatmentsByFlagSetsArgKeyIdx].(string); !ok { + return RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetsArgKeyIdx)} + } + + if t.BucketingKey, err = getOptionalRef[string](rpc.Args[TreatmentsByFlagSetsArgBucketingKeyIdx]); err != nil { + return RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetsArgBucketingKeyIdx)} + } + + rawFlagSetsList, ok := rpc.Args[TreatmentsByFlagSetsArgFlagSetsIdx].([]interface{}) + if !ok { + return RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetsArgFlagSetsIdx)} + + } + t.FlagSets, ok = sanitizeToStringSlice(rawFlagSetsList) + if !ok { + return RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetsArgFlagSetsIdx)} + } + + rawAttrs, err := getOptional[map[string]interface{}](rpc.Args[TreatmentsByFlagSetsArgAttributesIdx]) + if err != nil { + return RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetsArgAttributesIdx)} + } + t.Attributes = sanitizeAttributes(rawAttrs) + + return nil +} + const ( TrackArgKeyIdx int = 0 TrackArgTrafficTypeIdx int = 1 @@ -476,16 +542,16 @@ func sanitizeAttributes(attrs map[string]interface{}) map[string]interface{} { return attrs } -func sanitizeFeatureList(raw []interface{}) ([]string, bool) { - features := make([]string, 0, len(raw)) +func sanitizeToStringSlice(raw []interface{}) ([]string, bool) { + asStringSlice := make([]string, 0, len(raw)) for _, f := range raw { asStr, ok := f.(string) if !ok { return nil, false } - features = append(features, asStr) + asStringSlice = append(asStringSlice, asStr) } - return features, true + return asStringSlice, true } func tryInt[T int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64](x interface{}) (T, bool) { diff --git a/splitio/link/service/v1/clientmgr.go b/splitio/link/service/v1/clientmgr.go index ef2d9b2..4c5833f 100644 --- a/splitio/link/service/v1/clientmgr.go +++ b/splitio/link/service/v1/clientmgr.go @@ -128,6 +128,10 @@ func (m *ClientManager) dispatchRPC(rpc *protov1.RPC) (interface{}, error) { return m.handleGetTreatmentsByFlagSet(rpc, false) case protov1.OCTreatmentsWithConfigByFlagSet: return m.handleGetTreatmentsByFlagSet(rpc, true) + case protov1.OCTreatmentsByFlagSets: + return m.handleGetTreatmentsByFlagSets(rpc, false) + case protov1.OCTreatmentsWithConfigByFlagSets: + return m.handleGetTreatmentsByFlagSets(rpc, true) case protov1.OCTrack: return m.handleTrack(rpc) case protov1.OCSplitNames: @@ -273,6 +277,47 @@ func (m *ClientManager) handleGetTreatmentsByFlagSet(rpc *protov1.RPC, withConfi return response, nil } +func (m *ClientManager) handleGetTreatmentsByFlagSets(rpc *protov1.RPC, withConfig bool) (interface{}, error) { + + var args protov1.TreatmentsByFlagSetsArgs + if err := args.PopulateFromRPC(rpc); err != nil { + return nil, fmt.Errorf("error parsing treatments arguments: %w", err) + } + + res, err := m.splitSDK.TreatmentsByFlagSets(m.clientConfig, args.Key, args.BucketingKey, args.FlagSets, args.Attributes) + if err != nil { + return &protov1.ResponseWrapper[protov1.TreatmentsWithFeaturePayload]{Status: protov1.ResultInternalError}, err + } + + results := make(map[string]protov1.TreatmentPayload, 0) + for feature, evaluationResult := range res { + currentPayload := protov1.TreatmentPayload{ + Treatment: evaluationResult.Treatment, + } + + if m.clientConfig.ReturnImpressionData && evaluationResult.Impression != nil { + currentPayload.ListenerData = &protov1.ListenerExtraData{ + Label: evaluationResult.Impression.Label, + Timestamp: evaluationResult.Impression.Time, + ChangeNumber: evaluationResult.Impression.ChangeNumber, + } + } + + if withConfig { + currentPayload.Config = evaluationResult.Config + } + + results[feature] = currentPayload + } + + response := &protov1.ResponseWrapper[protov1.TreatmentsWithFeaturePayload]{ + Status: protov1.ResultOk, + Payload: protov1.TreatmentsWithFeaturePayload{Results: results}, + } + + return response, nil +} + func (m *ClientManager) handleTrack(rpc *protov1.RPC) (interface{}, error) { var args protov1.TrackArgs diff --git a/splitio/sdk/mocks/sdk.go b/splitio/sdk/mocks/sdk.go index 52328bf..bffb988 100644 --- a/splitio/sdk/mocks/sdk.go +++ b/splitio/sdk/mocks/sdk.go @@ -46,6 +46,18 @@ func (m *SDKMock) TreatmentsByFlagSet( return args.Get(0).(map[string]sdk.EvaluationResult), args.Error(1) } +// TreatmentsByFlagSets implements sdk.Interface +func (m *SDKMock) TreatmentsByFlagSets( + md *types.ClientConfig, + key string, + bucketingKey *string, + flagSets []string, + attributes map[string]interface{}, +) (map[string]sdk.EvaluationResult, error) { + args := m.Called(md, key, bucketingKey, flagSets, attributes) + return args.Get(0).(map[string]sdk.EvaluationResult), args.Error(1) +} + // Track implements sdk.Interface func (m *SDKMock) Track(cfg *types.ClientConfig, key string, trafficType string, eventType string, value *float64, properties map[string]interface{}) error { args := m.Called(cfg, key, trafficType, eventType, value, properties) diff --git a/splitio/sdk/sdk.go b/splitio/sdk/sdk.go index 8f0652b..4c682a7 100644 --- a/splitio/sdk/sdk.go +++ b/splitio/sdk/sdk.go @@ -39,6 +39,7 @@ type Interface interface { Treatment(cfg *types.ClientConfig, key string, bucketingKey *string, feature string, attributes map[string]interface{}) (*EvaluationResult, error) Treatments(cfg *types.ClientConfig, key string, bucketingKey *string, features []string, attributes map[string]interface{}) (map[string]EvaluationResult, error) TreatmentsByFlagSet(cfg *types.ClientConfig, key string, bucketingKey *string, flagSet string, attributes map[string]interface{}) (map[string]EvaluationResult, error) + TreatmentsByFlagSets(cfg *types.ClientConfig, key string, bucketingKey *string, flagSets []string, attributes map[string]interface{}) (map[string]EvaluationResult, error) Track(cfg *types.ClientConfig, key string, trafficType string, eventType string, value *float64, properties map[string]interface{}) error SplitNames() ([]string, error) Splits() ([]SplitView, error) @@ -169,6 +170,22 @@ func (i *Impl) TreatmentsByFlagSet(cfg *types.ClientConfig, key string, bk *stri return toRet, nil } +// TreatmentsByFlagSets implements Interface +func (i *Impl) TreatmentsByFlagSets(cfg *types.ClientConfig, key string, bk *string, flagSets []string, attributes Attributes) (map[string]EvaluationResult, error) { + + res := i.ev.EvaluateFeatureByFlagSets(key, bk, flagSets, attributes) + toRet := make(map[string]EvaluationResult, len(res.Evaluations)) + for feature, curr := range res.Evaluations { + var eres EvaluationResult + eres.Treatment = curr.Treatment + eres.Impression = i.handleImpression(key, bk, feature, &curr, cfg.Metadata) + eres.Config = curr.Config + toRet[feature] = eres + } + + return toRet, nil +} + func (i *Impl) Track(cfg *types.ClientConfig, key string, trafficType string, eventType string, value *float64, properties map[string]interface{}) error { // TODO(mredolatti): validate traffic type & truncate properties if needed diff --git a/splitio/sdk/sdk_test.go b/splitio/sdk/sdk_test.go index 3ba3726..ca8a2a4 100644 --- a/splitio/sdk/sdk_test.go +++ b/splitio/sdk/sdk_test.go @@ -283,6 +283,83 @@ func TestTreatmentsByFlagSet(t *testing.T) { } +func TestTreatmentsByFlagSets(t *testing.T) { + is, _ := storage.NewImpressionsQueue(100) + + ev := &mocks.EvaluatorMock{} + ev.On("EvaluateFeatureByFlagSets", "key1", (*string)(nil), []string{"set_1", "set_2"}, Attributes{"a": 1}). + Return(evaluator.Results{Evaluations: map[string]evaluator.Result{ + "f1": {Treatment: "on", Label: "label1", EvaluationTime: 1 * time.Millisecond, SplitChangeNumber: 123}, + "f2": {Treatment: "on", Label: "label2", EvaluationTime: 2 * time.Millisecond, SplitChangeNumber: 124}, + "f3": {Treatment: "on", Label: "label3", EvaluationTime: 3 * time.Millisecond, SplitChangeNumber: 125}, + }}). + Once() + + expectedImpressions := []dtos.Impression{ + {KeyName: "key1", BucketingKey: "", FeatureName: "f1", Treatment: "on", Label: "label1", ChangeNumber: 123}, + {KeyName: "key1", BucketingKey: "", FeatureName: "f2", Treatment: "on", Label: "label2", ChangeNumber: 124}, + {KeyName: "key1", BucketingKey: "", FeatureName: "f3", Treatment: "on", Label: "label3", ChangeNumber: 125}, + } + im := &mocks.ImpressionManagerMock{} + im.On("ProcessSingle", mock.Anything). + Run(func(args mock.Arguments) { + assertImpEq(t, &expectedImpressions[0], args.Get(0).(*dtos.Impression)) + }). + Return(true). + Once() + im.On("ProcessSingle", mock.Anything). + Run(func(args mock.Arguments) { + assertImpEq(t, &expectedImpressions[1], args.Get(0).(*dtos.Impression)) + }). + Return(true). + Once() + im.On("ProcessSingle", mock.Anything). + Run(func(args mock.Arguments) { + assertImpEq(t, &expectedImpressions[2], args.Get(0).(*dtos.Impression)) + }). + Return(true). + Once() + + client := &Impl{ + logger: logging.NewLogger(nil), + is: is, + ev: ev, + iq: im, + cfg: conf.Config{LabelsEnabled: true}, + } + + res, err := client.TreatmentsByFlagSets( + &types.ClientConfig{Metadata: types.ClientMetadata{ID: "some", SdkVersion: "go-1.2.3"}}, + "key1", nil, []string{"set_1", "set_2"}, Attributes{"a": 1}) + assert.Nil(t, err) + assert.Nil(t, res["f1"].Config) + assert.Nil(t, res["f2"].Config) + assert.Nil(t, res["f3"].Config) + assertImpEq(t, &expectedImpressions[0], res["f1"].Impression) + assertImpEq(t, &expectedImpressions[1], res["f2"].Impression) + assertImpEq(t, &expectedImpressions[2], res["f3"].Impression) + + err = is.RangeAndClear(func(md types.ClientMetadata, st *storage.LockingQueue[dtos.Impression]) { + assert.Equal(t, types.ClientMetadata{ID: "some", SdkVersion: "go-1.2.3"}, md) + assert.Equal(t, 3, st.Len()) + + var imps []dtos.Impression + n, err := st.Pop(3, &imps) + assert.Nil(t, nil) + assert.Equal(t, 3, n) + assert.Equal(t, 3, len(imps)) + assertImpEq(t, &expectedImpressions[0], &imps[0]) + assertImpEq(t, &expectedImpressions[1], &imps[1]) + assertImpEq(t, &expectedImpressions[2], &imps[2]) + n, err = st.Pop(1, &imps) + assert.Equal(t, 0, n) + assert.ErrorIs(t, err, storage.ErrQueueEmpty) + + }) + assert.Nil(t, err) + +} + func TestImpressionsQueueFull(t *testing.T) { logger := logging.NewLogger(nil) From 1ad06e98a69f867d436abfa9d4cbdbc4d091fa3d Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Tue, 2 Jan 2024 14:43:02 -0300 Subject: [PATCH 05/17] added defaultTreatment and sets in manager --- splitio/link/protocol/v1/responses.go | 14 +++++---- splitio/link/service/v1/clientmgr_test.go | 36 +++++++++++++---------- splitio/sdk/results.go | 14 +++++---- splitio/sdk/sdk.go | 14 +++++---- splitio/sdk/sdk_test.go | 24 ++++++++++----- 5 files changed, 60 insertions(+), 42 deletions(-) diff --git a/splitio/link/protocol/v1/responses.go b/splitio/link/protocol/v1/responses.go index 2f66d75..2139f36 100644 --- a/splitio/link/protocol/v1/responses.go +++ b/splitio/link/protocol/v1/responses.go @@ -33,12 +33,14 @@ type SplitNamesPayload struct { } type SplitPayload struct { - Name string `msgpack:"n"` - TrafficType string `msgpack:"t"` - Killed bool `msgpack:"k"` - Treatments []string `msgpack:"s"` - ChangeNumber int64 `msgpack:"c"` - Configs map[string]string `msgpack:"f"` + Name string `msgpack:"n"` + TrafficType string `msgpack:"t"` + Killed bool `msgpack:"k"` + Treatments []string `msgpack:"s"` + ChangeNumber int64 `msgpack:"c"` + Configs map[string]string `msgpack:"f"` + DefaultTreatment string `msgpack:"d"` + Sets []string `msgpack:"e"` } type SplitsPayload struct { diff --git a/splitio/link/service/v1/clientmgr_test.go b/splitio/link/service/v1/clientmgr_test.go index 2aed03f..f488076 100644 --- a/splitio/link/service/v1/clientmgr_test.go +++ b/splitio/link/service/v1/clientmgr_test.go @@ -323,14 +323,14 @@ func TestSplits(t *testing.T) { *args.Get(1).(*v1.RPC) = *proto1Mocks.NewSplitsRPC() }).Once() serializerMock.On("Serialize", proto1Mocks.NewSplitsResp(true, []v1.SplitPayload{ - {Name: "s1", TrafficType: "tt1", Killed: true, Treatments: []string{"on", "off"}, ChangeNumber: 1, Configs: map[string]string{"a": "x"}}, - {Name: "s2", TrafficType: "tt1", Killed: false, Treatments: []string{"on", "off"}, ChangeNumber: 1, Configs: map[string]string{"a": "y"}}, + {Name: "s1", TrafficType: "tt1", Killed: true, Treatments: []string{"on", "off"}, ChangeNumber: 1, Configs: map[string]string{"a": "x"}, DefaultTreatment: "on"}, + {Name: "s2", TrafficType: "tt1", Killed: false, Treatments: []string{"on", "off"}, ChangeNumber: 1, Configs: map[string]string{"a": "y"}, DefaultTreatment: "on", Sets: []string{"s1", "s2"}}, })).Return([]byte("successPayload"), nil).Once() sdkMock := &sdkMocks.SDKMock{} sdkMock.On("Splits").Return([]sdk.SplitView{ - {Name: "s1", TrafficType: "tt1", Killed: true, Treatments: []string{"on", "off"}, ChangeNumber: 1, Configs: map[string]string{"a": "x"}}, - {Name: "s2", TrafficType: "tt1", Killed: false, Treatments: []string{"on", "off"}, ChangeNumber: 1, Configs: map[string]string{"a": "y"}}, + {Name: "s1", TrafficType: "tt1", Killed: true, Treatments: []string{"on", "off"}, ChangeNumber: 1, Configs: map[string]string{"a": "x"}, DefaultTreatment: "on"}, + {Name: "s2", TrafficType: "tt1", Killed: false, Treatments: []string{"on", "off"}, ChangeNumber: 1, Configs: map[string]string{"a": "y"}, DefaultTreatment: "on", Sets: []string{"s1", "s2"}}, }, (error)(nil)).Once() logger := logging.NewLogger(nil) @@ -360,22 +360,26 @@ func TestSplit(t *testing.T) { *args.Get(1).(*v1.RPC) = *proto1Mocks.NewSplitRPC("s1") }).Once() serializerMock.On("Serialize", proto1Mocks.NewSplitResp(true, v1.SplitPayload{ - Name: "s1", - TrafficType: "tt1", - Killed: true, - Treatments: []string{"on", "off"}, - ChangeNumber: 1, - Configs: map[string]string{"a": "x"}, + Name: "s1", + TrafficType: "tt1", + Killed: true, + Treatments: []string{"on", "off"}, + ChangeNumber: 1, + Configs: map[string]string{"a": "x"}, + DefaultTreatment: "on", + Sets: []string{"s1", "s2"}, })).Return([]byte("successPayload"), nil).Once() sdkMock := &sdkMocks.SDKMock{} sdkMock.On("Split", "s1").Return(&sdk.SplitView{ - Name: "s1", - TrafficType: "tt1", - Killed: true, - Treatments: []string{"on", "off"}, - ChangeNumber: 1, - Configs: map[string]string{"a": "x"}, + Name: "s1", + TrafficType: "tt1", + Killed: true, + Treatments: []string{"on", "off"}, + ChangeNumber: 1, + Configs: map[string]string{"a": "x"}, + DefaultTreatment: "on", + Sets: []string{"s1", "s2"}, }, (error)(nil)).Once() logger := logging.NewLogger(nil) diff --git a/splitio/sdk/results.go b/splitio/sdk/results.go index 9c73acd..79dc972 100644 --- a/splitio/sdk/results.go +++ b/splitio/sdk/results.go @@ -9,10 +9,12 @@ type EvaluationResult struct { } type SplitView struct { - Name string - TrafficType string - Killed bool - Treatments []string - ChangeNumber int64 - Configs map[string]string + Name string + TrafficType string + Killed bool + Treatments []string + ChangeNumber int64 + Configs map[string]string + DefaultTreatment string + Sets []string } diff --git a/splitio/sdk/sdk.go b/splitio/sdk/sdk.go index da0d008..026c992 100644 --- a/splitio/sdk/sdk.go +++ b/splitio/sdk/sdk.go @@ -262,12 +262,14 @@ func splitToView(s *dtos.SplitDTO) *SplitView { } return &SplitView{ - Name: s.Name, - TrafficType: s.TrafficTypeName, - Killed: s.Killed, - ChangeNumber: s.ChangeNumber, - Configs: s.Configurations, - Treatments: treatments, + Name: s.Name, + TrafficType: s.TrafficTypeName, + Killed: s.Killed, + ChangeNumber: s.ChangeNumber, + Configs: s.Configurations, + Treatments: treatments, + DefaultTreatment: s.DefaultTreatment, + Sets: s.Sets, } } diff --git a/splitio/sdk/sdk_test.go b/splitio/sdk/sdk_test.go index 5b7c882..562c5fe 100644 --- a/splitio/sdk/sdk_test.go +++ b/splitio/sdk/sdk_test.go @@ -411,13 +411,21 @@ func TestSplitNames(t *testing.T) { func TestSplits(t *testing.T) { var ss mocks.SplitStorageMock ss.On("All").Return([]dtos.SplitDTO{ - {Name: "s1", TrafficTypeName: "tt1", ChangeNumber: 1, Conditions: []dtos.ConditionDTO{{Partitions: []dtos.PartitionDTO{{Treatment: "a"}, {Treatment: "b"}}}}}, { - Name: "s2", - TrafficTypeName: "tt1", - ChangeNumber: 1, - Conditions: []dtos.ConditionDTO{{Partitions: []dtos.PartitionDTO{{Treatment: "a"}, {Treatment: "b"}}}}, - Configurations: map[string]string{"a": "conf1", "b": "conf2"}, + Name: "s1", + TrafficTypeName: "tt1", + ChangeNumber: 1, + Conditions: []dtos.ConditionDTO{{Partitions: []dtos.PartitionDTO{{Treatment: "a"}, {Treatment: "b"}}}}, + DefaultTreatment: "a", + Sets: []string{"s1", "s2"}, + }, + { + Name: "s2", + TrafficTypeName: "tt1", + ChangeNumber: 1, + Conditions: []dtos.ConditionDTO{{Partitions: []dtos.PartitionDTO{{Treatment: "a"}, {Treatment: "b"}}}}, + Configurations: map[string]string{"a": "conf1", "b": "conf2"}, + DefaultTreatment: "a", }, }).Once() @@ -426,8 +434,8 @@ func TestSplits(t *testing.T) { splits, err := c.Splits() assert.Nil(t, err) assert.Equal(t, []SplitView{ - {Name: "s1", TrafficType: "tt1", Killed: false, Treatments: []string{"a", "b"}, ChangeNumber: 1}, - {Name: "s2", TrafficType: "tt1", Killed: false, Treatments: []string{"a", "b"}, ChangeNumber: 1, Configs: map[string]string{"a": "conf1", "b": "conf2"}}, + {Name: "s1", TrafficType: "tt1", Killed: false, Treatments: []string{"a", "b"}, ChangeNumber: 1, DefaultTreatment: "a", Sets: []string{"s1", "s2"}}, + {Name: "s2", TrafficType: "tt1", Killed: false, Treatments: []string{"a", "b"}, ChangeNumber: 1, Configs: map[string]string{"a": "conf1", "b": "conf2"}, DefaultTreatment: "a"}, }, splits) } From 0fd60cdc365cc6367da47af76a65686efed6c00f Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Tue, 9 Jan 2024 11:29:45 -0300 Subject: [PATCH 06/17] created results with fixed size --- splitio/link/service/v1/clientmgr.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/splitio/link/service/v1/clientmgr.go b/splitio/link/service/v1/clientmgr.go index ef2d9b2..9fd182d 100644 --- a/splitio/link/service/v1/clientmgr.go +++ b/splitio/link/service/v1/clientmgr.go @@ -244,7 +244,7 @@ func (m *ClientManager) handleGetTreatmentsByFlagSet(rpc *protov1.RPC, withConfi return &protov1.ResponseWrapper[protov1.TreatmentsWithFeaturePayload]{Status: protov1.ResultInternalError}, err } - results := make(map[string]protov1.TreatmentPayload, 0) + results := make(map[string]protov1.TreatmentPayload, len(res)) for feature, evaluationResult := range res { currentPayload := protov1.TreatmentPayload{ Treatment: evaluationResult.Treatment, From 64bf13c61dff783fb0c9a9b6dd638d626ae32861 Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Tue, 9 Jan 2024 11:32:50 -0300 Subject: [PATCH 07/17] created results with fixed size --- splitio/link/service/v1/clientmgr.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/splitio/link/service/v1/clientmgr.go b/splitio/link/service/v1/clientmgr.go index 5f13cea..b66df1d 100644 --- a/splitio/link/service/v1/clientmgr.go +++ b/splitio/link/service/v1/clientmgr.go @@ -289,7 +289,7 @@ func (m *ClientManager) handleGetTreatmentsByFlagSets(rpc *protov1.RPC, withConf return &protov1.ResponseWrapper[protov1.TreatmentsWithFeaturePayload]{Status: protov1.ResultInternalError}, err } - results := make(map[string]protov1.TreatmentPayload, 0) + results := make(map[string]protov1.TreatmentPayload, len(res)) for feature, evaluationResult := range res { currentPayload := protov1.TreatmentPayload{ Treatment: evaluationResult.Treatment, From ae62ed502936759983bd6e2df27fd4da2eba2b0e Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Tue, 9 Jan 2024 12:32:04 -0300 Subject: [PATCH 08/17] added testing coverage --- splitio/link/protocol/v1/mocks/mocks.go | 28 +++ splitio/link/protocol/v1/rpcs.go | 2 +- splitio/link/protocol/v1/rpcs_test.go | 130 ++++++++++++++ splitio/link/service/v1/clientmgr_test.go | 200 ++++++++++++++++++++++ 4 files changed, 359 insertions(+), 1 deletion(-) diff --git a/splitio/link/protocol/v1/mocks/mocks.go b/splitio/link/protocol/v1/mocks/mocks.go index bb63661..cf56663 100644 --- a/splitio/link/protocol/v1/mocks/mocks.go +++ b/splitio/link/protocol/v1/mocks/mocks.go @@ -139,6 +139,34 @@ func NewTreatmentsResp(ok bool, data []sdk.EvaluationResult) *v1.ResponseWrapper } } +func NewTreatmentsByFlagSetResp(ok bool, data map[string]sdk.EvaluationResult) *v1.ResponseWrapper[v1.TreatmentsWithFeaturePayload] { + res := v1.ResultOk + if !ok { + res = v1.ResultInternalError + } + + payload := make(map[string]v1.TreatmentPayload, len(data)) + for f, r := range data { + p := v1.TreatmentPayload{ + Treatment: r.Treatment, + Config: r.Config, + } + if r.Impression != nil { + p.ListenerData = &v1.ListenerExtraData{ + Label: r.Impression.Label, + Timestamp: r.Impression.Time, + ChangeNumber: r.Impression.ChangeNumber, + } + } + payload[f] = p + } + + return &v1.ResponseWrapper[v1.TreatmentsWithFeaturePayload]{ + Status: res, + Payload: v1.TreatmentsWithFeaturePayload{Results: payload}, + } +} + func NewTrackResp(ok bool) *v1.ResponseWrapper[v1.TrackPayload] { res := v1.ResultOk if !ok { diff --git a/splitio/link/protocol/v1/rpcs.go b/splitio/link/protocol/v1/rpcs.go index 6cc1477..2a8a741 100644 --- a/splitio/link/protocol/v1/rpcs.go +++ b/splitio/link/protocol/v1/rpcs.go @@ -339,8 +339,8 @@ func (t *TreatmentsByFlagSetsArgs) PopulateFromRPC(rpc *RPC) error { rawFlagSetsList, ok := rpc.Args[TreatmentsByFlagSetsArgFlagSetsIdx].([]interface{}) if !ok { return RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetsArgFlagSetsIdx)} - } + t.FlagSets, ok = sanitizeToStringSlice(rawFlagSetsList) if !ok { return RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetsArgFlagSetsIdx)} diff --git a/splitio/link/protocol/v1/rpcs_test.go b/splitio/link/protocol/v1/rpcs_test.go index 843c720..b618672 100644 --- a/splitio/link/protocol/v1/rpcs_test.go +++ b/splitio/link/protocol/v1/rpcs_test.go @@ -16,6 +16,10 @@ func TestOpStringify(t *testing.T) { assert.Equal(t, "treatment-with-config", OCTreatmentWithConfig.String()) assert.Equal(t, "treatments", OCTreatments.String()) assert.Equal(t, "treatments-with-config", OCTreatmentsWithConfig.String()) + assert.Equal(t, "treatments-by-flag-set", OCTreatmentsByFlagSet.String()) + assert.Equal(t, "treatments-with-config-by-flag-set", OCTreatmentsWithConfigByFlagSet.String()) + assert.Equal(t, "treatments-by-flag-sets", OCTreatmentsByFlagSets.String()) + assert.Equal(t, "treatments-with-config-by-flag-sets", OCTreatmentsWithConfigByFlagSets.String()) assert.Equal(t, "track", OCTrack.String()) assert.Equal(t, "split-names", OCSplitNames.String()) assert.Equal(t, "split", OCSplit.String()) @@ -177,6 +181,132 @@ func TestTreatmentsRPCParsing(t *testing.T) { assert.Nil(t, r.Attributes) } +func TestTreatmentsByFlagSetRPCParsing(t *testing.T) { + var r TreatmentsByFlagSetArgs + assert.Equal(t, + RPCParseError{Code: PECOpCodeMismatch}, + r.PopulateFromRPC(&RPC{RPCBase: protocol.RPCBase{Version: protocol.V1}, OpCode: OCRegister, Args: nil}), + ) + assert.Equal(t, + RPCParseError{Code: PECWrongArgCount}, + r.PopulateFromRPC(&RPC{RPCBase: protocol.RPCBase{Version: protocol.V1}, OpCode: OCTreatmentsByFlagSet, Args: []interface{}{}}), + ) + assert.Equal(t, + RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetArgKeyIdx)}, + r.PopulateFromRPC(&RPC{RPCBase: protocol.RPCBase{Version: protocol.V1}, OpCode: OCTreatmentsByFlagSet, Args: []interface{}{nil, nil, nil, nil}}), + ) + assert.Equal(t, + RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetArgBucketingKeyIdx)}, + r.PopulateFromRPC(&RPC{RPCBase: protocol.RPCBase{Version: protocol.V1}, OpCode: OCTreatmentsByFlagSet, Args: []interface{}{"key", 123, nil, nil}}), + ) + assert.Equal(t, + RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetArgFlagSetIdx)}, + r.PopulateFromRPC(&RPC{RPCBase: protocol.RPCBase{Version: protocol.V1}, OpCode: OCTreatmentsByFlagSet, Args: []interface{}{"key", "bk", 123, nil}}), + ) + assert.Equal(t, + RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetArgAttributesIdx)}, + r.PopulateFromRPC(&RPC{ + RPCBase: protocol.RPCBase{Version: protocol.V1}, + OpCode: OCTreatmentsByFlagSet, + Args: []interface{}{"key", "bk", "set", 123}}), + ) + + err := r.PopulateFromRPC(&RPC{ + RPCBase: protocol.RPCBase{Version: protocol.V1}, + OpCode: OCTreatmentsByFlagSet, + Args: []interface{}{"key", "bk", "set", map[string]interface{}{"a": 1}}}) + assert.Nil(t, err) + assert.Equal(t, "key", r.Key) + assert.Equal(t, lang.Ref("bk"), r.BucketingKey) + assert.Equal(t, "set", r.FlagSet) + assert.Equal(t, map[string]interface{}{"a": int64(1)}, r.Attributes) + + // nil bucketing key + err = r.PopulateFromRPC(&RPC{ + RPCBase: protocol.RPCBase{Version: protocol.V1}, + OpCode: OCTreatmentsByFlagSet, + Args: []interface{}{"key", nil, "set", map[string]interface{}{"a": 1}}}) + assert.Nil(t, err) + assert.Equal(t, "key", r.Key) + assert.Nil(t, r.BucketingKey) + assert.Equal(t, "set", r.FlagSet) + assert.Equal(t, map[string]interface{}{"a": int64(1)}, r.Attributes) + + // nil attributes + err = r.PopulateFromRPC(&RPC{ + RPCBase: protocol.RPCBase{Version: protocol.V1}, + OpCode: OCTreatmentsByFlagSet, + Args: []interface{}{"key", "bk", "set", nil}}) + assert.Nil(t, err) + assert.Equal(t, "key", r.Key) + assert.Equal(t, lang.Ref("bk"), r.BucketingKey) + assert.Equal(t, "set", r.FlagSet) + assert.Nil(t, r.Attributes) +} + +func TestTreatmentsByFlagSetsRPCParsing(t *testing.T) { + var r TreatmentsByFlagSetsArgs + assert.Equal(t, + RPCParseError{Code: PECOpCodeMismatch}, + r.PopulateFromRPC(&RPC{RPCBase: protocol.RPCBase{Version: protocol.V1}, OpCode: OCRegister, Args: nil}), + ) + assert.Equal(t, + RPCParseError{Code: PECWrongArgCount}, + r.PopulateFromRPC(&RPC{RPCBase: protocol.RPCBase{Version: protocol.V1}, OpCode: OCTreatmentsByFlagSets, Args: []interface{}{}}), + ) + assert.Equal(t, + RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetsArgKeyIdx)}, + r.PopulateFromRPC(&RPC{RPCBase: protocol.RPCBase{Version: protocol.V1}, OpCode: OCTreatmentsByFlagSets, Args: []interface{}{nil, nil, nil, nil}}), + ) + assert.Equal(t, + RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetsArgBucketingKeyIdx)}, + r.PopulateFromRPC(&RPC{RPCBase: protocol.RPCBase{Version: protocol.V1}, OpCode: OCTreatmentsByFlagSets, Args: []interface{}{"key", 123, nil, nil}}), + ) + assert.Equal(t, + RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetsArgFlagSetsIdx)}, + r.PopulateFromRPC(&RPC{RPCBase: protocol.RPCBase{Version: protocol.V1}, OpCode: OCTreatmentsByFlagSets, Args: []interface{}{"key", "bk", 123, nil}}), + ) + assert.Equal(t, + RPCParseError{Code: PECInvalidArgType, Data: int64(TreatmentsByFlagSetsArgAttributesIdx)}, + r.PopulateFromRPC(&RPC{ + RPCBase: protocol.RPCBase{Version: protocol.V1}, + OpCode: OCTreatmentsByFlagSets, + Args: []interface{}{"key", "bk", []interface{}{"set_1", "set_2"}, 123}}), + ) + + err := r.PopulateFromRPC(&RPC{ + RPCBase: protocol.RPCBase{Version: protocol.V1}, + OpCode: OCTreatmentsByFlagSets, + Args: []interface{}{"key", "bk", []interface{}{"set_1", "set_2"}, map[string]interface{}{"a": 1}}}) + assert.Nil(t, err) + assert.Equal(t, "key", r.Key) + assert.Equal(t, lang.Ref("bk"), r.BucketingKey) + assert.Equal(t, []string{"set_1", "set_2"}, r.FlagSets) + assert.Equal(t, map[string]interface{}{"a": int64(1)}, r.Attributes) + + // nil bucketing key + err = r.PopulateFromRPC(&RPC{ + RPCBase: protocol.RPCBase{Version: protocol.V1}, + OpCode: OCTreatmentsByFlagSets, + Args: []interface{}{"key", nil, []interface{}{"set_1", "set_2"}, map[string]interface{}{"a": 1}}}) + assert.Nil(t, err) + assert.Equal(t, "key", r.Key) + assert.Nil(t, r.BucketingKey) + assert.Equal(t, []string{"set_1", "set_2"}, r.FlagSets) + assert.Equal(t, map[string]interface{}{"a": int64(1)}, r.Attributes) + + // nil attributes + err = r.PopulateFromRPC(&RPC{ + RPCBase: protocol.RPCBase{Version: protocol.V1}, + OpCode: OCTreatmentsByFlagSets, + Args: []interface{}{"key", "bk", []interface{}{"set_1", "set_2"}, nil}}) + assert.Nil(t, err) + assert.Equal(t, "key", r.Key) + assert.Equal(t, lang.Ref("bk"), r.BucketingKey) + assert.Equal(t, []string{"set_1", "set_2"}, r.FlagSets) + assert.Nil(t, r.Attributes) +} + func TestTrackRPCParsing(t *testing.T) { var r TrackArgs assert.Equal(t, diff --git a/splitio/link/service/v1/clientmgr_test.go b/splitio/link/service/v1/clientmgr_test.go index 2aed03f..b9a013a 100644 --- a/splitio/link/service/v1/clientmgr_test.go +++ b/splitio/link/service/v1/clientmgr_test.go @@ -236,6 +236,206 @@ func TestRegisterWithImpsAndTreatmentHappyPath(t *testing.T) { assert.Nil(t, err) } +func TestRegisterAndTreatmentsByFlagSetHappyPath(t *testing.T) { + rawConnMock := &transferMocks.RawConnMock{} + rawConnMock.On("ReceiveMessage").Return([]byte("registrationMessage"), nil).Once() + rawConnMock.On("SendMessage", []byte("successRegistration")).Return(nil).Once() + rawConnMock.On("ReceiveMessage").Return([]byte("treatmentsByFlagSetMessage"), nil).Once() + rawConnMock.On("SendMessage", []byte("successPayload")).Return(nil).Once() + rawConnMock.On("ReceiveMessage").Return([]byte(nil), io.EOF).Once() + + serializerMock := &serializerMocks.SerializerMock{} + serializerMock.On("Parse", []byte("registrationMessage"), mock.Anything).Return(nil).Run(func(args mock.Arguments) { + *args.Get(1).(*v1.RPC) = v1.RPC{ + RPCBase: protocol.RPCBase{Version: protocol.V1}, + OpCode: v1.OCRegister, + Args: []interface{}{"someID", "some_sdk-1.2.3", uint64(0)}, + } + }).Once() + serializerMock.On("Serialize", proto1Mocks.NewRegisterResp(true)).Return([]byte("successRegistration"), nil).Once() + serializerMock.On("Parse", []byte("treatmentsByFlagSetMessage"), mock.Anything).Return(nil).Run(func(args mock.Arguments) { + *args.Get(1).(*v1.RPC) = v1.RPC{ + RPCBase: protocol.RPCBase{Version: protocol.V1}, + OpCode: v1.OCTreatmentsByFlagSet, + Args: []interface{}{"key", nil, "set", map[string]interface{}(nil)}, + } + }).Once() + serializerMock.On("Serialize", proto1Mocks.NewTreatmentsByFlagSetResp(true, map[string]sdk.EvaluationResult{ + "feat1": {Treatment: "on"}, "feat2": {Treatment: "off"}, "feat3": {Treatment: "control"}, + })).Return([]byte("successPayload"), nil).Once() + + sdkMock := &sdkMocks.SDKMock{} + sdkMock. + On( + "TreatmentsByFlagSet", + &types.ClientConfig{Metadata: types.ClientMetadata{ID: "someID", SdkVersion: "some_sdk-1.2.3"}}, + "key", + (*string)(nil), + "set", + map[string]interface{}(nil), + ).Return(map[string]sdk.EvaluationResult{ + "feat1": {Treatment: "on"}, + "feat2": {Treatment: "off"}, + "feat3": {Treatment: "control"}, + }, nil).Once() + + logger := logging.NewLogger(nil) + cm := NewClientManager(rawConnMock, logger, sdkMock, serializerMock) + err := cm.handleClientInteractions() + assert.Nil(t, err) +} + +func TestRegisterAndTreatmentsWithConfigByFlagSetHappyPath(t *testing.T) { + rawConnMock := &transferMocks.RawConnMock{} + rawConnMock.On("ReceiveMessage").Return([]byte("registrationMessage"), nil).Once() + rawConnMock.On("SendMessage", []byte("successRegistration")).Return(nil).Once() + rawConnMock.On("ReceiveMessage").Return([]byte("treatmentsWithConfigByFlagSetMessage"), nil).Once() + rawConnMock.On("SendMessage", []byte("successPayload")).Return(nil).Once() + rawConnMock.On("ReceiveMessage").Return([]byte(nil), io.EOF).Once() + + var strCfg = "what" + + serializerMock := &serializerMocks.SerializerMock{} + serializerMock.On("Parse", []byte("registrationMessage"), mock.Anything).Return(nil).Run(func(args mock.Arguments) { + *args.Get(1).(*v1.RPC) = v1.RPC{ + RPCBase: protocol.RPCBase{Version: protocol.V1}, + OpCode: v1.OCRegister, + Args: []interface{}{"someID", "some_sdk-1.2.3", uint64(0)}, + } + }).Once() + serializerMock.On("Serialize", proto1Mocks.NewRegisterResp(true)).Return([]byte("successRegistration"), nil).Once() + serializerMock.On("Parse", []byte("treatmentsWithConfigByFlagSetMessage"), mock.Anything).Return(nil).Run(func(args mock.Arguments) { + *args.Get(1).(*v1.RPC) = v1.RPC{ + RPCBase: protocol.RPCBase{Version: protocol.V1}, + OpCode: v1.OCTreatmentsWithConfigByFlagSet, + Args: []interface{}{"key", nil, "set", map[string]interface{}(nil)}, + } + }).Once() + serializerMock.On("Serialize", proto1Mocks.NewTreatmentsByFlagSetResp(true, map[string]sdk.EvaluationResult{ + "feat1": {Treatment: "on"}, "feat2": {Treatment: "off"}, "feat3": {Treatment: "control", Config: &strCfg}, + })).Return([]byte("successPayload"), nil).Once() + + sdkMock := &sdkMocks.SDKMock{} + sdkMock. + On( + "TreatmentsByFlagSet", + &types.ClientConfig{Metadata: types.ClientMetadata{ID: "someID", SdkVersion: "some_sdk-1.2.3"}}, + "key", + (*string)(nil), + "set", + map[string]interface{}(nil), + ).Return(map[string]sdk.EvaluationResult{ + "feat1": {Treatment: "on"}, + "feat2": {Treatment: "off"}, + "feat3": {Treatment: "control", Config: &strCfg}, + }, nil).Once() + + logger := logging.NewLogger(nil) + cm := NewClientManager(rawConnMock, logger, sdkMock, serializerMock) + err := cm.handleClientInteractions() + assert.Nil(t, err) +} + +func TestRegisterAndTreatmentsByFlagSetstHappyPath(t *testing.T) { + rawConnMock := &transferMocks.RawConnMock{} + rawConnMock.On("ReceiveMessage").Return([]byte("registrationMessage"), nil).Once() + rawConnMock.On("SendMessage", []byte("successRegistration")).Return(nil).Once() + rawConnMock.On("ReceiveMessage").Return([]byte("treatmentsByFlagSetsMessage"), nil).Once() + rawConnMock.On("SendMessage", []byte("successPayload")).Return(nil).Once() + rawConnMock.On("ReceiveMessage").Return([]byte(nil), io.EOF).Once() + + serializerMock := &serializerMocks.SerializerMock{} + serializerMock.On("Parse", []byte("registrationMessage"), mock.Anything).Return(nil).Run(func(args mock.Arguments) { + *args.Get(1).(*v1.RPC) = v1.RPC{ + RPCBase: protocol.RPCBase{Version: protocol.V1}, + OpCode: v1.OCRegister, + Args: []interface{}{"someID", "some_sdk-1.2.3", uint64(0)}, + } + }).Once() + serializerMock.On("Serialize", proto1Mocks.NewRegisterResp(true)).Return([]byte("successRegistration"), nil).Once() + serializerMock.On("Parse", []byte("treatmentsByFlagSetsMessage"), mock.Anything).Return(nil).Run(func(args mock.Arguments) { + *args.Get(1).(*v1.RPC) = v1.RPC{ + RPCBase: protocol.RPCBase{Version: protocol.V1}, + OpCode: v1.OCTreatmentsByFlagSets, + Args: []interface{}{"key", nil, []interface{}{"set_1", "set_2"}, map[string]interface{}(nil)}, + } + }).Once() + serializerMock.On("Serialize", proto1Mocks.NewTreatmentsByFlagSetResp(true, map[string]sdk.EvaluationResult{ + "feat1": {Treatment: "on"}, "feat2": {Treatment: "off"}, "feat3": {Treatment: "control"}, + })).Return([]byte("successPayload"), nil).Once() + + sdkMock := &sdkMocks.SDKMock{} + sdkMock. + On( + "TreatmentsByFlagSets", + &types.ClientConfig{Metadata: types.ClientMetadata{ID: "someID", SdkVersion: "some_sdk-1.2.3"}}, + "key", + (*string)(nil), + []string{"set_1", "set_2"}, + map[string]interface{}(nil), + ).Return(map[string]sdk.EvaluationResult{ + "feat1": {Treatment: "on"}, + "feat2": {Treatment: "off"}, + "feat3": {Treatment: "control"}, + }, nil).Once() + + logger := logging.NewLogger(nil) + cm := NewClientManager(rawConnMock, logger, sdkMock, serializerMock) + err := cm.handleClientInteractions() + assert.Nil(t, err) +} + +func TestRegisterAndTreatmentsWithConfigByFlagSetsHappyPath(t *testing.T) { + rawConnMock := &transferMocks.RawConnMock{} + rawConnMock.On("ReceiveMessage").Return([]byte("registrationMessage"), nil).Once() + rawConnMock.On("SendMessage", []byte("successRegistration")).Return(nil).Once() + rawConnMock.On("ReceiveMessage").Return([]byte("treatmentsWithConfigByFlagSetsMessage"), nil).Once() + rawConnMock.On("SendMessage", []byte("successPayload")).Return(nil).Once() + rawConnMock.On("ReceiveMessage").Return([]byte(nil), io.EOF).Once() + + var strCfg = "what" + + serializerMock := &serializerMocks.SerializerMock{} + serializerMock.On("Parse", []byte("registrationMessage"), mock.Anything).Return(nil).Run(func(args mock.Arguments) { + *args.Get(1).(*v1.RPC) = v1.RPC{ + RPCBase: protocol.RPCBase{Version: protocol.V1}, + OpCode: v1.OCRegister, + Args: []interface{}{"someID", "some_sdk-1.2.3", uint64(0)}, + } + }).Once() + serializerMock.On("Serialize", proto1Mocks.NewRegisterResp(true)).Return([]byte("successRegistration"), nil).Once() + serializerMock.On("Parse", []byte("treatmentsWithConfigByFlagSetsMessage"), mock.Anything).Return(nil).Run(func(args mock.Arguments) { + *args.Get(1).(*v1.RPC) = v1.RPC{ + RPCBase: protocol.RPCBase{Version: protocol.V1}, + OpCode: v1.OCTreatmentsWithConfigByFlagSets, + Args: []interface{}{"key", nil, []interface{}{"set_1", "set_2"}, map[string]interface{}(nil)}, + } + }).Once() + serializerMock.On("Serialize", proto1Mocks.NewTreatmentsByFlagSetResp(true, map[string]sdk.EvaluationResult{ + "feat1": {Treatment: "on"}, "feat2": {Treatment: "off"}, "feat3": {Treatment: "control", Config: &strCfg}, + })).Return([]byte("successPayload"), nil).Once() + + sdkMock := &sdkMocks.SDKMock{} + sdkMock. + On( + "TreatmentsByFlagSets", + &types.ClientConfig{Metadata: types.ClientMetadata{ID: "someID", SdkVersion: "some_sdk-1.2.3"}}, + "key", + (*string)(nil), + []string{"set_1", "set_2"}, + map[string]interface{}(nil), + ).Return(map[string]sdk.EvaluationResult{ + "feat1": {Treatment: "on"}, + "feat2": {Treatment: "off"}, + "feat3": {Treatment: "control", Config: &strCfg}, + }, nil).Once() + + logger := logging.NewLogger(nil) + cm := NewClientManager(rawConnMock, logger, sdkMock, serializerMock) + err := cm.handleClientInteractions() + assert.Nil(t, err) +} + func TestTrack(t *testing.T) { rawConnMock := &transferMocks.RawConnMock{} rawConnMock.On("ReceiveMessage").Return([]byte("registrationMessage"), nil).Once() From 82e701fa1095212bcca1c2e540c50f1231dbd8e5 Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Tue, 9 Jan 2024 14:49:41 -0300 Subject: [PATCH 09/17] added coverage on Encode --- splitio/link/protocol/v1/rpcs_test.go | 24 ++++++++++++++++++++++++ splitio/link/service/v1/clientmgr.go | 4 ++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/splitio/link/protocol/v1/rpcs_test.go b/splitio/link/protocol/v1/rpcs_test.go index b618672..1b36a66 100644 --- a/splitio/link/protocol/v1/rpcs_test.go +++ b/splitio/link/protocol/v1/rpcs_test.go @@ -499,6 +499,30 @@ func TestRPCEncoding(t *testing.T) { assert.Equal(t, tsa.Features, encodedTsA[TreatmentsArgFeaturesIdx].([]string)) assert.Equal(t, tsa.Attributes, encodedTsA[TreatmentsArgAttributesIdx].(map[string]interface{})) + tsfa := TreatmentsByFlagSetArgs{ + Key: "someKey", + BucketingKey: lang.Ref("someBucketing"), + FlagSet: "set", + Attributes: map[string]interface{}{"some": "attribute"}, + } + encodedTsfA := tsfa.Encode() + assert.Equal(t, tsfa.Key, encodedTsfA[TreatmentsByFlagSetArgKeyIdx].(string)) + assert.Equal(t, *tsfa.BucketingKey, encodedTsfA[TreatmentsByFlagSetArgBucketingKeyIdx].(string)) + assert.Equal(t, tsfa.FlagSet, encodedTsfA[TreatmentsByFlagSetArgFlagSetIdx].(string)) + assert.Equal(t, tsfa.Attributes, encodedTsfA[TreatmentsByFlagSetArgAttributesIdx].(map[string]interface{})) + + tsfsa := TreatmentsByFlagSetsArgs{ + Key: "someKey", + BucketingKey: lang.Ref("someBucketing"), + FlagSets: []string{"set_1", "set_2"}, + Attributes: map[string]interface{}{"some": "attribute"}, + } + encodedTsfsA := tsfsa.Encode() + assert.Equal(t, tsfsa.Key, encodedTsfsA[TreatmentsByFlagSetsArgKeyIdx].(string)) + assert.Equal(t, *tsfsa.BucketingKey, encodedTsfsA[TreatmentsByFlagSetsArgBucketingKeyIdx].(string)) + assert.Equal(t, tsfsa.FlagSets, encodedTsfsA[TreatmentsByFlagSetsArgFlagSetsIdx].([]string)) + assert.Equal(t, tsfsa.Attributes, encodedTsfsA[TreatmentsByFlagSetsArgAttributesIdx].(map[string]interface{})) + tra := TrackArgs{ Key: "someKey", TrafficType: "someTrafficType", diff --git a/splitio/link/service/v1/clientmgr.go b/splitio/link/service/v1/clientmgr.go index b66df1d..f80ca3f 100644 --- a/splitio/link/service/v1/clientmgr.go +++ b/splitio/link/service/v1/clientmgr.go @@ -240,7 +240,7 @@ func (m *ClientManager) handleGetTreatmentsByFlagSet(rpc *protov1.RPC, withConfi var args protov1.TreatmentsByFlagSetArgs if err := args.PopulateFromRPC(rpc); err != nil { - return nil, fmt.Errorf("error parsing treatments arguments: %w", err) + return nil, fmt.Errorf("error parsing treatmentsByFlagSet arguments: %w", err) } res, err := m.splitSDK.TreatmentsByFlagSet(m.clientConfig, args.Key, args.BucketingKey, args.FlagSet, args.Attributes) @@ -281,7 +281,7 @@ func (m *ClientManager) handleGetTreatmentsByFlagSets(rpc *protov1.RPC, withConf var args protov1.TreatmentsByFlagSetsArgs if err := args.PopulateFromRPC(rpc); err != nil { - return nil, fmt.Errorf("error parsing treatments arguments: %w", err) + return nil, fmt.Errorf("error parsing treatmentsByFlagSets arguments: %w", err) } res, err := m.splitSDK.TreatmentsByFlagSets(m.clientConfig, args.Key, args.BucketingKey, args.FlagSets, args.Attributes) From 2c7e15d71c1189d6e456667628bd8675f09948dc Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Tue, 9 Jan 2024 14:58:12 -0300 Subject: [PATCH 10/17] props for sonar --- sonar-project.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonar-project.properties b/sonar-project.properties index 2ec9177..af730cf 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -3,6 +3,6 @@ sonar.sources=. sonar.tests=. sonar.test.inclusions=**/*_test.go sonar.go.coverage.reportPaths=coverage.out -sonar.coverage.exclusions=**/mocks/** +sonar.coverage.exclusions=**/mocks/**,**/*_test.go sonar.links.ci=https://github.com/splitio/splitd sonar.links.scm=https://github.com/splitio/splitd/actions From 80fae647a11452d89b851d61603a81aa58b7154a Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Tue, 9 Jan 2024 15:17:43 -0300 Subject: [PATCH 11/17] updated sonar project --- sonar-project.properties | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sonar-project.properties b/sonar-project.properties index af730cf..6d1ccb1 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -3,6 +3,7 @@ sonar.sources=. sonar.tests=. sonar.test.inclusions=**/*_test.go sonar.go.coverage.reportPaths=coverage.out -sonar.coverage.exclusions=**/mocks/**,**/*_test.go +sonar.coverage.exclusions=**/mocks/** sonar.links.ci=https://github.com/splitio/splitd sonar.links.scm=https://github.com/splitio/splitd/actions +sonar.cpd.exclusions=**/mocks/**,**/*_test.go From 0d2ade10d1104c7a838c08b596ba2c695a988226 Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Wed, 17 Jan 2024 17:24:45 -0300 Subject: [PATCH 12/17] added input validation --- cmd/splitd/main.go | 1 + splitio/commitsha.go | 2 +- splitio/conf/splitd.go | 6 +++++- splitio/sdk/conf/conf.go | 1 + splitio/sdk/conf/conf_test.go | 1 + splitio/sdk/sdk.go | 10 +++++++++- 6 files changed, 18 insertions(+), 3 deletions(-) diff --git a/cmd/splitd/main.go b/cmd/splitd/main.go index 82a991b..104317d 100644 --- a/cmd/splitd/main.go +++ b/cmd/splitd/main.go @@ -24,6 +24,7 @@ func main() { fmt.Println("error reading config: ", err.Error()) os.Exit(1) } + fmt.Println("cfg.SDK.FlagSetsFilter", cfg.SDK.FlagSetsFilter) handleFlags(cfg) loggerCfg, err := cfg.Logger.ToLoggerOptions() diff --git a/splitio/commitsha.go b/splitio/commitsha.go index 51dcc58..4a36418 100644 --- a/splitio/commitsha.go +++ b/splitio/commitsha.go @@ -1,3 +1,3 @@ package splitio -const CommitSHA = "b98165e" +const CommitSHA = "80fae64" diff --git a/splitio/conf/splitd.go b/splitio/conf/splitd.go index 41d1c18..e09a461 100644 --- a/splitio/conf/splitd.go +++ b/splitio/conf/splitd.go @@ -127,7 +127,8 @@ type SDK struct { URLs URLs `yaml:"urls"` FeatureFlags FeatureFlags `yaml:"featureFlags"` Impressions Impressions `yaml:"impressions"` - Events Events `yank:"events"` + Events Events `yaml:"events"` + FlagSetsFilter []string `yaml:"flagSetsFilter"` } func (s *SDK) PopulateWithDefaults() { @@ -139,6 +140,7 @@ func (s *SDK) PopulateWithDefaults() { s.FeatureFlags.PopulateWithDefaults() s.Impressions.PopulateWithDefaults() s.Events.PopulateWithDefaults() + s.FlagSetsFilter = []string{} } type FeatureFlags struct { @@ -209,6 +211,8 @@ func (s *SDK) ToSDKConf() *sdkConf.Config { lang.SetIfNotEmpty(&cfg.Events.QueueSize, s.Events.QueueSize) lang.MapIfNotNil(&cfg.Events.SyncPeriod, s.Events.RefreshRateSeconds, durationFromSeconds) s.URLs.updateSDKConfURLs(&cfg.URLs) + // lang.SetIfNotNil(&cfg.FlagSetsFilter, s.FlagSetsFilter) + fmt.Println("TOSDKCONFIG", s.FlagSetsFilter) return cfg } diff --git a/splitio/sdk/conf/conf.go b/splitio/sdk/conf/conf.go index 1ad1045..ec255ec 100644 --- a/splitio/sdk/conf/conf.go +++ b/splitio/sdk/conf/conf.go @@ -114,6 +114,7 @@ func DefaultConfig() *Config { Streaming: "https://streaming.split.io/sse", Telemetry: "https://telemetry.split.io/api/v1", }, + FlagSetsFilter: []string{}, } } diff --git a/splitio/sdk/conf/conf_test.go b/splitio/sdk/conf/conf_test.go index f3e87ea..438e858 100644 --- a/splitio/sdk/conf/conf_test.go +++ b/splitio/sdk/conf/conf_test.go @@ -32,4 +32,5 @@ func TestSDKConf(t *testing.T) { assert.Equal(t, int64(dc.Segments.UpdateBufferSize), adv.SegmentUpdateQueueSize) assert.Equal(t, int(dc.Splits.SyncPeriod.Seconds()), adv.SplitsRefreshRate) assert.Equal(t, int(dc.Segments.SyncPeriod.Seconds()), adv.SegmentsRefreshRate) + assert.Equal(t, dc.FlagSetsFilter, adv.FlagSetsFilter) } diff --git a/splitio/sdk/sdk.go b/splitio/sdk/sdk.go index 82c064c..f5aeab1 100644 --- a/splitio/sdk/sdk.go +++ b/splitio/sdk/sdk.go @@ -72,7 +72,15 @@ func New(logger logging.LoggerInterface, apikey string, c *conf.Config) (*Impl, md := dtos.Metadata{SDKVersion: fmt.Sprintf("splitd-%s", splitio.Version)} advCfg := c.ToAdvancedConfig() - flagSetsFilter := flagsets.NewFlagSetFilter(advCfg.FlagSetsFilter) + flagSets, errs := flagsets.SanitizeMany(advCfg.FlagSetsFilter) + if len(errs) != 0 { + for _, err := range errs { + if errType, ok := err.(dtos.FlagSetValidatonError); ok { + logger.Warning(errType.Message) + } + } + } + flagSetsFilter := flagsets.NewFlagSetFilter(flagSets) stores := setupStorages(c, flagSetsFilter) impc, err := setupImpressionsComponents(&c.Impressions, stores.telemetry) From 67fb0dbea5621cbf4be129a1abc734c2ff77d5f0 Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Wed, 17 Jan 2024 17:55:37 -0300 Subject: [PATCH 13/17] check before setting flagSetsFilter --- cmd/splitd/main.go | 1 - splitio/commitsha.go | 2 +- splitio/conf/splitd.go | 4 +++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cmd/splitd/main.go b/cmd/splitd/main.go index 104317d..82a991b 100644 --- a/cmd/splitd/main.go +++ b/cmd/splitd/main.go @@ -24,7 +24,6 @@ func main() { fmt.Println("error reading config: ", err.Error()) os.Exit(1) } - fmt.Println("cfg.SDK.FlagSetsFilter", cfg.SDK.FlagSetsFilter) handleFlags(cfg) loggerCfg, err := cfg.Logger.ToLoggerOptions() diff --git a/splitio/commitsha.go b/splitio/commitsha.go index 4a36418..6138c92 100644 --- a/splitio/commitsha.go +++ b/splitio/commitsha.go @@ -1,3 +1,3 @@ package splitio -const CommitSHA = "80fae64" +const CommitSHA = "0d2ade1" diff --git a/splitio/conf/splitd.go b/splitio/conf/splitd.go index e09a461..cb740ab 100644 --- a/splitio/conf/splitd.go +++ b/splitio/conf/splitd.go @@ -212,7 +212,9 @@ func (s *SDK) ToSDKConf() *sdkConf.Config { lang.MapIfNotNil(&cfg.Events.SyncPeriod, s.Events.RefreshRateSeconds, durationFromSeconds) s.URLs.updateSDKConfURLs(&cfg.URLs) // lang.SetIfNotNil(&cfg.FlagSetsFilter, s.FlagSetsFilter) - fmt.Println("TOSDKCONFIG", s.FlagSetsFilter) + if len(s.FlagSetsFilter) > 0 { + cfg.FlagSetsFilter = s.FlagSetsFilter + } return cfg } From 3f311749d1f122874ab25ead8704416716755b9d Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Wed, 17 Jan 2024 18:16:27 -0300 Subject: [PATCH 14/17] moved sanitization for flagsets before setting the config --- splitio/commitsha.go | 2 +- splitio/sdk/conf/conf.go | 13 +++++++++++++ splitio/sdk/sdk.go | 10 +--------- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/splitio/commitsha.go b/splitio/commitsha.go index 6138c92..ed77921 100644 --- a/splitio/commitsha.go +++ b/splitio/commitsha.go @@ -1,3 +1,3 @@ package splitio -const CommitSHA = "0d2ade1" +const CommitSHA = "67fb0db" diff --git a/splitio/sdk/conf/conf.go b/splitio/sdk/conf/conf.go index ec255ec..020455f 100644 --- a/splitio/sdk/conf/conf.go +++ b/splitio/sdk/conf/conf.go @@ -4,6 +4,8 @@ import ( "time" "github.com/splitio/go-split-commons/v5/conf" + "github.com/splitio/go-split-commons/v5/dtos" + "github.com/splitio/go-split-commons/v5/flagsets" ) const ( @@ -125,5 +127,16 @@ func (c *Config) Normalize() []string { c.Impressions.SyncPeriod = minimumImpressionsRefreshRate } + // Sanitize flagsets and append erros into warnings for logging purposes + sanitizedFlagSets, warns := flagsets.SanitizeMany(c.FlagSetsFilter) + if len(warns) != 0 { + for _, err := range warns { + if errType, ok := err.(dtos.FlagSetValidatonError); ok { + warnings = append(warnings, errType.Message) + } + } + } + c.FlagSetsFilter = sanitizedFlagSets + return warnings } diff --git a/splitio/sdk/sdk.go b/splitio/sdk/sdk.go index f5aeab1..82c064c 100644 --- a/splitio/sdk/sdk.go +++ b/splitio/sdk/sdk.go @@ -72,15 +72,7 @@ func New(logger logging.LoggerInterface, apikey string, c *conf.Config) (*Impl, md := dtos.Metadata{SDKVersion: fmt.Sprintf("splitd-%s", splitio.Version)} advCfg := c.ToAdvancedConfig() - flagSets, errs := flagsets.SanitizeMany(advCfg.FlagSetsFilter) - if len(errs) != 0 { - for _, err := range errs { - if errType, ok := err.(dtos.FlagSetValidatonError); ok { - logger.Warning(errType.Message) - } - } - } - flagSetsFilter := flagsets.NewFlagSetFilter(flagSets) + flagSetsFilter := flagsets.NewFlagSetFilter(advCfg.FlagSetsFilter) stores := setupStorages(c, flagSetsFilter) impc, err := setupImpressionsComponents(&c.Impressions, stores.telemetry) From 15ef04fb8a1b63053c8843498ace66a1ecaba953 Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Tue, 23 Jan 2024 11:37:46 -0300 Subject: [PATCH 15/17] fixed test --- splitio/commitsha.go | 2 +- splitio/conf/splitd.go | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/splitio/commitsha.go b/splitio/commitsha.go index ed77921..b66a6e0 100644 --- a/splitio/commitsha.go +++ b/splitio/commitsha.go @@ -1,3 +1,3 @@ package splitio -const CommitSHA = "67fb0db" +const CommitSHA = "8a9ba4b" diff --git a/splitio/conf/splitd.go b/splitio/conf/splitd.go index cb740ab..7ef227d 100644 --- a/splitio/conf/splitd.go +++ b/splitio/conf/splitd.go @@ -140,7 +140,6 @@ func (s *SDK) PopulateWithDefaults() { s.FeatureFlags.PopulateWithDefaults() s.Impressions.PopulateWithDefaults() s.Events.PopulateWithDefaults() - s.FlagSetsFilter = []string{} } type FeatureFlags struct { From 74f88bb30cb54e66cf78dd2514bd4ecf06a51e73 Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Thu, 25 Jan 2024 12:19:48 -0300 Subject: [PATCH 16/17] prepare release --- .github/dependabot.yaml | 10 ++++++++++ CHANGES | 12 ++++++++++++ splitio/commitsha.go | 2 +- splitio/version.go | 2 +- 4 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 .github/dependabot.yaml diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 0000000..f8a529b --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,10 @@ +--- +version: 2 + +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "daily" + reviewers: + - "splitio/sdk" diff --git a/CHANGES b/CHANGES index 7f54419..b62ef2c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,15 @@ +1.2.0 (Jan 25, 2024): +- 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. + - getTreatmentsByFlagSet and getTreatmentsByFlagSets + - getTreatmentWithConfigByFlagSets and getTreatmentsWithConfigByFlagSets + - Added a new optional Split 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. +- Updated the following SDK manager method to expose flag sets on flag views: + - Added `defaultTreatment` property to the `SplitView` object returned by the `split` and `splits` methods of the SDK manager. +- Added go-split-commons/v5 library as a dependency. + - Added evaluator from commons. +- Removed go-client dependency. + 1.1.1 (Nov 10, 2023): - Updated startup logic to remove dead sockets instead of failing immediately if the socket file exists - Fix memory leak when accepting an incoming connection. diff --git a/splitio/commitsha.go b/splitio/commitsha.go index b66a6e0..2a9b130 100644 --- a/splitio/commitsha.go +++ b/splitio/commitsha.go @@ -1,3 +1,3 @@ package splitio -const CommitSHA = "8a9ba4b" +const CommitSHA = "15ef04f" diff --git a/splitio/version.go b/splitio/version.go index 14a44ce..92af151 100644 --- a/splitio/version.go +++ b/splitio/version.go @@ -1,3 +1,3 @@ package splitio -const Version = "1.2.0-rc1" +const Version = "1.2.0" From 8848f3829b4da91ca14a9eb2df8b2eb10d1ab8ca Mon Sep 17 00:00:00 2001 From: Matias Melograno Date: Thu, 25 Jan 2024 12:25:07 -0300 Subject: [PATCH 17/17] updated changes --- .github/dependabot.yaml | 2 +- CHANGES | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index f8a529b..075ff53 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -5,6 +5,6 @@ updates: - package-ecosystem: "github-actions" directory: "/" schedule: - interval: "daily" + interval: "weekly" reviewers: - "splitio/sdk" diff --git a/CHANGES b/CHANGES index b62ef2c..5b7c582 100644 --- a/CHANGES +++ b/CHANGES @@ -6,7 +6,7 @@ - Added a new optional Split 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. - Updated the following SDK manager method to expose flag sets on flag views: - Added `defaultTreatment` property to the `SplitView` object returned by the `split` and `splits` methods of the SDK manager. -- Added go-split-commons/v5 library as a dependency. +- Upgraded go-split-commons/v5 library as a dependency. - Added evaluator from commons. - Removed go-client dependency.