Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
15041ee
Merge branch 'main' of github.com:splitio/go-split-commons
mmelograno May 14, 2024
8dd4d78
Merge branch 'main' of github.com:splitio/go-split-commons
mmelograno Apr 25, 2025
bfac7f1
Merge branch 'main' of github.com:splitio/go-split-commons
mmelograno Sep 30, 2025
b0b22c3
added logger mock
mmelograno Sep 30, 2025
a139785
Added ReplacedAll method in split storage
nmayorsplit Oct 2, 2025
1bb0526
Added asserts in test cases
nmayorsplit Oct 2, 2025
4b205e7
Merge pull request #242 from splitio/FME-10103
nmayorsplit Oct 2, 2025
2579b0c
updated tests
mmelograno Oct 3, 2025
fc10566
fixed test
mmelograno Oct 3, 2025
7521960
fixed pop test
mmelograno Oct 3, 2025
843301f
merged with latest
mmelograno Oct 3, 2025
711dc30
Merge pull request #241 from splitio/task/loggerMock
mmelograno Oct 3, 2025
5ccec65
Merge branch 'spec-version-proxy' of github.com:splitio/go-split-comm…
mmelograno Oct 6, 2025
ef4bc94
decoupled logic
mmelograno Oct 6, 2025
b8df563
Add response interface for split change
nmayorsplit Oct 7, 2025
20568cc
Delete .vscode/launch.json
nmayorsplit Oct 7, 2025
96054a5
Add local response
nmayorsplit Oct 7, 2025
37db2a1
Remove extra functions from splitchangewrapper
nmayorsplit Oct 8, 2025
a2e103c
Updates test cases to asserts
nmayorsplit Oct 8, 2025
33be54b
Merge pull request #243 from splitio/FME-10442
nmayorsplit Oct 8, 2025
2fa65c8
draft of retry in case is proxy
mmelograno Oct 8, 2025
a88deaf
Added function to know if the sdk is using a proxy or not
nmayorsplit Oct 9, 2025
cfc0e97
added logic to retry
mmelograno Oct 9, 2025
5f4176f
clean code
mmelograno Oct 9, 2025
499f747
added next call for until since==till
mmelograno Oct 9, 2025
18e02f9
fixed logic
mmelograno Oct 13, 2025
e58bddd
added test
mmelograno Oct 13, 2025
96dea75
renamed method
mmelograno Oct 14, 2025
17ff98a
Add method in the interface
nmayorsplit Oct 14, 2025
c7ae6a7
Updated isProxy function
nmayorsplit Oct 14, 2025
a3a515d
Merge pull request #244 from splitio/FME-10474
nmayorsplit Oct 14, 2025
f406824
Added rule-based segment replace function in the storage
nmayorsplit Oct 14, 2025
473108f
Updated params to create updater
nmayorsplit Oct 15, 2025
85ddb19
Merge pull request #245 from splitio/task/retryFetcher
mmelograno Oct 15, 2025
814c898
Updated to v8
nmayorsplit Oct 15, 2025
ae69092
Merge branch 'spec-version-proxy' of github.com:splitio/go-split-comm…
mmelograno Oct 15, 2025
039f2f9
updated toolkit
mmelograno Oct 15, 2025
acbfdbc
forwarded err in logic
mmelograno Oct 15, 2025
045e9d7
Merge branch 'main' into spec-version-proxy
nmayorsplit Oct 16, 2025
01d5565
Remove logs when 404 and removed extra param for isProxy
nmayorsplit Oct 16, 2025
2846c30
Merge branch 'spec-version-proxy' of github.com:splitio/go-split-comm…
mmelograno Oct 16, 2025
7976fa1
resolving spec version from fetchOptions
mmelograno Oct 16, 2025
de7c602
Updated client
nmayorsplit Oct 16, 2025
e5554be
added coverage
mmelograno Oct 16, 2025
2ebda7b
Merge branch 'spec-version-proxy' of github.com:splitio/go-split-comm…
mmelograno Oct 16, 2025
330171c
Updated sotrages and logic when processFFChange
nmayorsplit Oct 20, 2025
2b389da
Updated constants
nmayorsplit Oct 20, 2025
2736845
Updated conditions
nmayorsplit Oct 20, 2025
3f87bfc
fixed test
mmelograno Oct 20, 2025
41a437a
Merge branch 'FME-10531' of github.com:splitio/go-split-commons into …
mmelograno Oct 20, 2025
6dbf562
added pcn not cn
mmelograno Oct 20, 2025
6c57997
fixed tests due lack o matcher type
mmelograno Oct 20, 2025
1d8038d
small changes
mmelograno Oct 20, 2025
0c5ee48
Updated ReplaceAll
nmayorsplit Oct 20, 2025
b8fa6ac
Merge pull request #248 from splitio/FME-10531
nmayorsplit Oct 21, 2025
5ab40ce
Updated with last changes
nmayorsplit Oct 21, 2025
8073e34
Merge pull request #246 from splitio/FME-10623
mmelograno Oct 21, 2025
f68a272
Updated ci
nmayorsplit Oct 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
fetch-depth: 0

- name: Set up Go version
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: '1.21'

Expand Down
6 changes: 6 additions & 0 deletions dtos/split.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ type FeatureFlagsDTO struct {
Splits []SplitDTO `json:"d"`
}

type SplitsDTO struct {
Since int64 `json:"since"`
Till int64 `json:"till"`
Splits []SplitDTO `json:"splits"`
}

type RuleBasedSegmentsDTO struct {
Since int64 `json:"s"`
Till int64 `json:"t"`
Expand Down
206 changes: 206 additions & 0 deletions dtos/splitchangewrapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
package dtos

import (
"encoding/json"
)

// FFResponse is an interface that abstracts the differences between different versions of feature flag responses.
type FFResponse interface {
NeedsAnotherFetch() bool
RuleBasedSegments() []RuleBasedSegmentDTO
FeatureFlags() []SplitDTO
FFTill() int64
RBTill() int64
FFSince() int64
RBSince() int64
}

// FFResponseLegacy handles the legacy format of feature flag responses.
type FFResponseLegacy struct {
SplitChanges SplitsDTO
}

// NewFFResponseLegacy creates a new FFResponseLegacy instance from the provided JSON data.
func NewFFResponseLegacy(data []byte) (FFResponse, error) {
var splitChangesDto SplitsDTO
err := json.Unmarshal(data, &splitChangesDto)
if err == nil {
return &FFResponseLegacy{
SplitChanges: splitChangesDto,
}, nil
}
return nil, err
}

// NeedsAnotherFetch checks if another fetch is needed based on the since and till values.
func (ffLegacy *FFResponseLegacy) NeedsAnotherFetch() bool {
return ffLegacy.SplitChanges.Since == ffLegacy.SplitChanges.Till
}

// FeatureFlags returns the list of feature flags (splits) from the response.
func (ffLegacy *FFResponseLegacy) FeatureFlags() []SplitDTO {
return ffLegacy.SplitChanges.Splits
}

// RuleBasedSegments returns an empty list as legacy responses do not contain rule-based segments.
func (ffLegacy *FFResponseLegacy) RuleBasedSegments() []RuleBasedSegmentDTO {
return []RuleBasedSegmentDTO{}
}

// FFTill returns the till value for feature flags.
func (ffLegacy *FFResponseLegacy) FFTill() int64 {
return ffLegacy.SplitChanges.Till
}

// RBTill returns 0 as legacy responses do not contain rule-based segments.
func (ffLegacy *FFResponseLegacy) RBTill() int64 {
return 0
}

// FFSince returns the since value for feature flags.
func (ffLegacy *FFResponseLegacy) FFSince() int64 {
return ffLegacy.SplitChanges.Since
}

// RBSince returns 0 as legacy responses do not contain rule-based segments.
func (ffLegacy *FFResponseLegacy) RBSince() int64 {
return 0
}

// FFResponseV13 handles the version 1.3 format of feature flag responses.
type FFResponseV13 struct {
SplitChanges SplitChangesDTO
}

// NewFFResponseV13 creates a new FFResponseV13 instance from the provided JSON data.
func NewFFResponseV13(data []byte) (FFResponse, error) {
var splitChangesDto SplitChangesDTO
err := json.Unmarshal(data, &splitChangesDto)
if err == nil {
return &FFResponseV13{
SplitChanges: splitChangesDto,
}, nil
}
return nil, err
}

// FeatureFlags returns the list of feature flags (splits) from the response.
func (f13 *FFResponseV13) FeatureFlags() []SplitDTO {
return f13.SplitChanges.FeatureFlags.Splits
}

// RuleBasedSegments returns the list of rule-based segments from the response.
func (f13 *FFResponseV13) RuleBasedSegments() []RuleBasedSegmentDTO {
return f13.SplitChanges.RuleBasedSegments.RuleBasedSegments
}

// NeedsAnotherFetch checks if another fetch is needed based on the since and till values for both feature flags and rule-based segments.
func (f13 FFResponseV13) NeedsAnotherFetch() bool {
return f13.SplitChanges.FeatureFlags.Since == f13.SplitChanges.FeatureFlags.Till && f13.SplitChanges.RuleBasedSegments.Since == f13.SplitChanges.RuleBasedSegments.Till
}

// FFTill returns the till value for feature flags.
func (f13 *FFResponseV13) FFTill() int64 {
return f13.SplitChanges.FeatureFlags.Till
}

// RBTill returns the till value for rule-based segments.
func (f13 *FFResponseV13) RBTill() int64 {
return f13.SplitChanges.RuleBasedSegments.Till
}

// RBSince returns the since value for rule-based segments.
func (f13 *FFResponseV13) RBSince() int64 {
return f13.SplitChanges.RuleBasedSegments.Since
}

// FFSince returns the since value for feature flags.
func (f13 *FFResponseV13) FFSince() int64 {
return f13.SplitChanges.FeatureFlags.Since
}

// FFResponseLocalV13 is a local version of FFResponseV13 for internal use.
type FFResponseLocalV13 struct {
SplitChanges SplitChangesDTO
}

// NewFFResponseLocalV13 creates a new FFResponseLocalV13 instance from the provided JSON data.
func NewFFResponseLocalV13(data []byte) (*FFResponseLocalV13, error) {
var splitChangesDto SplitChangesDTO
err := json.Unmarshal(data, &splitChangesDto)
if err == nil {
return &FFResponseLocalV13{
SplitChanges: splitChangesDto,
}, nil
}
return nil, err
}

// FeatureFlags returns the list of feature flags (splits) from the response.
func (f *FFResponseLocalV13) FeatureFlags() []SplitDTO {
return f.SplitChanges.FeatureFlags.Splits
}

// RuleBasedSegments returns the list of rule-based segments from the response.
func (f *FFResponseLocalV13) RuleBasedSegments() []RuleBasedSegmentDTO {
return f.SplitChanges.RuleBasedSegments.RuleBasedSegments
}

// NeedsAnotherFetch checks if another fetch is needed based on the since and till values for both feature flags and rule-based segments.
func (f FFResponseLocalV13) NeedsAnotherFetch() bool {
return f.SplitChanges.FeatureFlags.Since == f.SplitChanges.FeatureFlags.Till && f.SplitChanges.RuleBasedSegments.Since == f.SplitChanges.RuleBasedSegments.Till
}

// FFTill returns the till value for feature flags.
func (f *FFResponseLocalV13) FFTill() int64 {
return f.SplitChanges.FeatureFlags.Till
}

// RBTill returns the till value for rule-based segments.
func (f *FFResponseLocalV13) RBTill() int64 {
return f.SplitChanges.RuleBasedSegments.Till
}

// RBSince returns the since value for rule-based segments.
func (f *FFResponseLocalV13) RBSince() int64 {
return f.SplitChanges.RuleBasedSegments.Since
}

// FFSince returns the since value for feature flags.
func (f *FFResponseLocalV13) SetFFTill(till int64) {
f.SplitChanges.FeatureFlags.Till = till
}

// SetFFSince sets the since value for feature flags.
func (f *FFResponseLocalV13) SetFFSince(since int64) {
f.SplitChanges.FeatureFlags.Since = since
}

// SetRBTill sets the till value for rule-based segments.
func (f *FFResponseLocalV13) SetRBTill(till int64) {
f.SplitChanges.RuleBasedSegments.Till = till
}

// FFSince returns the since value for feature flags.
func (f *FFResponseLocalV13) FFSince() int64 {
return f.SplitChanges.FeatureFlags.Since
}

// SetRBSince sets the since value for rule-based segments.
func (f *FFResponseLocalV13) SetRBSince(since int64) {
f.SplitChanges.RuleBasedSegments.Since = since
}

// ReplaceFF replaces the feature flags (splits) in the response with the provided list.
func (f *FFResponseLocalV13) ReplaceFF(featureFlags []SplitDTO) {
f.SplitChanges.FeatureFlags.Splits = featureFlags
}

// ReplaceRB replaces the rule-based segments in the response with the provided list.
func (f *FFResponseLocalV13) ReplaceRB(ruleBasedSegments []RuleBasedSegmentDTO) {
f.SplitChanges.RuleBasedSegments.RuleBasedSegments = ruleBasedSegments
}

var _ FFResponse = (*FFResponseLegacy)(nil)
var _ FFResponse = (*FFResponseV13)(nil)
var _ FFResponse = (*FFResponseLocalV13)(nil)
150 changes: 150 additions & 0 deletions dtos/splitchangewrapper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package dtos

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestFFResponseLegacy(t *testing.T) {
some, err := NewFFResponseLegacy([]byte(`{wrong json}`))
assert.Nil(t, some)
assert.NotNil(t, err)

ok, err := NewFFResponseLegacy([]byte(`{"since":1,"till":2,"splits":[{"name":"split1"},{"name":"split2"}]}`))
assert.NotNil(t, ok)
assert.Nil(t, err)
assert.Equal(t, int64(2), ok.FFTill())
assert.Equal(t, int64(0), ok.RBTill())
assert.Equal(t, int64(1), ok.FFSince())
assert.Equal(t, int64(0), ok.RBSince())
assert.False(t, ok.NeedsAnotherFetch())
assert.Len(t, ok.FeatureFlags(), 2)
assert.Empty(t, ok.RuleBasedSegments())

noFetch, err := NewFFResponseLegacy([]byte(`{"since":2,"till":2,"splits":[]}`))
assert.NotNil(t, noFetch)
assert.Nil(t, err)
assert.Equal(t, int64(2), noFetch.FFTill())
assert.Equal(t, int64(0), noFetch.RBTill())
assert.Equal(t, int64(2), noFetch.FFSince())
assert.Equal(t, int64(0), noFetch.RBSince())
assert.True(t, noFetch.NeedsAnotherFetch())
assert.Len(t, noFetch.FeatureFlags(), 0)
assert.Empty(t, noFetch.RuleBasedSegments())
}

func TestFFResponseLatest(t *testing.T) {
some, err := NewFFResponseV13([]byte(`{wrong json}`))
assert.Nil(t, some)
assert.NotNil(t, err)

ok, err := NewFFResponseV13([]byte(`{
"ff":{
"s":1,
"t":2,
"d":[{"name":"split1"},{"name":"split2"}]
},
"rbs":{
"s":3,
"t":4,
"d":[{"name":"rb1"},{"name":"rb2"},{"name":"rb3"}]
}
}`))
assert.NotNil(t, ok)
assert.Nil(t, err)
assert.Equal(t, int64(2), ok.FFTill())
assert.Equal(t, int64(4), ok.RBTill())
assert.Equal(t, int64(1), ok.FFSince())
assert.Equal(t, int64(3), ok.RBSince())
assert.Len(t, ok.FeatureFlags(), 2)
assert.Len(t, ok.RuleBasedSegments(), 3)
assert.False(t, ok.NeedsAnotherFetch())

noFetch, err := NewFFResponseV13([]byte(`{
"ff":{
"s":2,
"t":2,
"d":[]
},
"rbs":{
"s":4,
"t":4,
"d":[]
}
}`))
assert.NotNil(t, noFetch)
assert.Nil(t, err)
assert.Equal(t, int64(2), noFetch.FFTill())
assert.Equal(t, int64(4), noFetch.RBTill())
assert.Equal(t, int64(2), noFetch.FFSince())
assert.Equal(t, int64(4), noFetch.RBSince())
assert.Len(t, noFetch.FeatureFlags(), 0)
assert.Len(t, noFetch.RuleBasedSegments(), 0)
assert.True(t, noFetch.NeedsAnotherFetch())
}

func TestFFResponseLocalV13(t *testing.T) {
some, err := NewFFResponseLocalV13([]byte(`{wrong json}`))
assert.Nil(t, some)
assert.NotNil(t, err)

ok, err := NewFFResponseLocalV13([]byte(`{
"ff":{
"s":1,
"t":2,
"d":[{"name":"split1"},{"name":"split2"}]
},
"rbs":{
"s":3,
"t":4,
"d":[{"name":"rb1"},{"name":"rb2"},{"name":"rb3"}]
}
}`))
assert.NotNil(t, ok)
assert.Nil(t, err)
assert.Equal(t, int64(2), ok.FFTill())
assert.Equal(t, int64(4), ok.RBTill())
assert.Equal(t, int64(1), ok.FFSince())
assert.Equal(t, int64(3), ok.RBSince())
assert.Len(t, ok.FeatureFlags(), 2)
assert.Len(t, ok.RuleBasedSegments(), 3)
assert.False(t, ok.NeedsAnotherFetch())

ok.SetFFTill(5)
ok.SetFFSince(5)
ok.SetRBSince(5)
ok.SetRBTill(5)
assert.Equal(t, int64(5), ok.FFTill())
assert.Equal(t, int64(5), ok.RBTill())
assert.Equal(t, int64(5), ok.FFSince())
assert.Equal(t, int64(5), ok.RBSince())
ok.ReplaceFF([]SplitDTO{{Name: "other"}})
ok.ReplaceRB([]RuleBasedSegmentDTO{{Name: "other_rb"}})
assert.Len(t, ok.FeatureFlags(), 1)
assert.Len(t, ok.RuleBasedSegments(), 1)
assert.Equal(t, "other", ok.FeatureFlags()[0].Name)
assert.Equal(t, "other_rb", ok.RuleBasedSegments()[0].Name)

noFetch, err := NewFFResponseLocalV13([]byte(`{
"ff":{
"s":2,
"t":2,
"d":[]
},
"rbs":{
"s":4,
"t":4,
"d":[]
}
}`))
assert.NotNil(t, noFetch)
assert.Nil(t, err)
assert.Equal(t, int64(2), noFetch.FFTill())
assert.Equal(t, int64(4), noFetch.RBTill())
assert.Equal(t, int64(2), noFetch.FFSince())
assert.Equal(t, int64(4), noFetch.RBSince())
assert.Len(t, noFetch.FeatureFlags(), 0)
assert.Len(t, noFetch.RuleBasedSegments(), 0)
assert.True(t, noFetch.NeedsAnotherFetch())
}
8 changes: 4 additions & 4 deletions engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import (
"fmt"
"math"

"github.com/splitio/go-split-commons/v7/engine/evaluator/impressionlabels"
"github.com/splitio/go-split-commons/v7/engine/grammar"
"github.com/splitio/go-split-commons/v7/engine/grammar/constants"
"github.com/splitio/go-split-commons/v7/engine/hash"
"github.com/splitio/go-split-commons/v8/engine/evaluator/impressionlabels"
"github.com/splitio/go-split-commons/v8/engine/grammar"
"github.com/splitio/go-split-commons/v8/engine/grammar/constants"
"github.com/splitio/go-split-commons/v8/engine/hash"

"github.com/splitio/go-toolkit/v5/hasher"
"github.com/splitio/go-toolkit/v5/logging"
Expand Down
Loading
Loading