Skip to content

Commit

Permalink
feat: update support for passthrough rollouts
Browse files Browse the repository at this point in the history
  • Loading branch information
suthar26 committed May 8, 2024
1 parent 006f345 commit 12c0f18
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 55 deletions.
1 change: 1 addition & 0 deletions api/model_public_project.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ type Project struct {
type ProjectSettings struct {
EdgeDB EdgeDBSettings `json:"edgeDB"`
OptIn OptInSettings `json:"optIn"`
DisablePassthroughRollouts bool `json:"disablePassthroughRollouts"`
}

type EdgeDBSettings struct {
Expand Down
12 changes: 10 additions & 2 deletions bucketing/bucketing.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,15 @@ func doesUserPassRollout(rollout Rollout, boundedHash float64) bool {

func evaluateSegmentationForFeature(config *configBody, feature *ConfigFeature, user api.PopulatedUser, clientCustomData map[string]interface{}) *Target {
for _, target := range feature.Configuration.Targets {
passthroughEnabled := !config.Project.Settings.DisablePassthroughRollouts
doesUserPassthrough := true
if target.Rollout != nil && passthroughEnabled {
boundedHash := generateBoundedHashes(user.UserId, target.Id)
rolloutHash := boundedHash.RolloutHash
doesUserPassthrough = doesUserPassRollout(*target.Rollout, rolloutHash)
}
operator := target.Audience.Filters
if operator.Evaluate(config.Audiences, user, clientCustomData) {
if operator.Evaluate(config.Audiences, user, clientCustomData) && doesUserPassthrough {
return target
}
}
Expand All @@ -127,8 +134,9 @@ func doesUserQualifyForFeature(config *configBody, feature *ConfigFeature, user

boundedHashes := generateBoundedHashes(user.UserId, target.Id)
rolloutHash := boundedHashes.RolloutHash
passthroughEnabled := !config.Project.Settings.DisablePassthroughRollouts

if target.Rollout != nil && !doesUserPassRollout(*target.Rollout, rolloutHash) {
if target.Rollout != nil && !passthroughEnabled && !doesUserPassRollout(*target.Rollout, rolloutHash) {
return targetAndHashes{}, ErrUserRollout
}
return targetAndHashes{
Expand Down
73 changes: 72 additions & 1 deletion bucketing/bucketing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package bucketing

import (
_ "embed"
"encoding/json"
"fmt"
"testing"
"time"
Expand Down Expand Up @@ -53,7 +54,15 @@ func TestBucketing_RolloutGatesUser(t *testing.T) {
Email: "[email protected]",
}.GetPopulatedUser(&api.PlatformData{})

config, err := newConfig(test_config, "", "", "")
var test_config_json map[string]interface{}
err := json.Unmarshal(test_config, &test_config_json)
require.NoError(t, err)
test_config_json["project"].(map[string]interface{})["settings"].(map[string]interface{})["disablePassthroughRollouts"] = true
var updated_config []byte
updated_config, err = json.Marshal(test_config_json)
require.NoError(t, err)

config, err := newConfig(updated_config, "", "", "")
require.NoError(t, err)

feature := config.GetFeatureForVariableId("61538237b0a70b58ae6af71f")
Expand Down Expand Up @@ -81,6 +90,68 @@ func TestBucketing_RolloutGatesUser(t *testing.T) {
require.Equal(t, "61536f468fd67f0091982533", target.Target.Id)
}

func TestBucketing_RolloutPassthroughUser(t *testing.T) {
user := api.User{
UserId: "does_not_pass_rollout",
Email: "[email protected]",
CustomData: map[string]interface{}{
"favouriteFood": "pizza",
"favouriteDrink": "coffee",
},
}.GetPopulatedUser(&api.PlatformData{
PlatformVersion: "1.1.2",
})

var test_config_json map[string]interface{}
err := json.Unmarshal(test_config, &test_config_json)
require.NoError(t, err)
test_config_json["project"].(map[string]interface{})["settings"].(map[string]interface{})["disablePassthroughRollouts"] = false
var updated_config []byte
updated_config, err = json.Marshal(test_config_json)
require.NoError(t, err)

config, err := newConfig(updated_config, "", "", "")
require.NoError(t, err)

feature := config.GetFeatureForVariableId("61538237b0a70b58ae6af71f")

feature.Configuration.Targets[0].Rollout = &Rollout{
Type: "gradual",
StartPercentage: 0,
StartDate: time.Now().Add(time.Hour * -1),
Stages: []RolloutStage{
{
Type: "linear",
Date: time.Now().Add(time.Hour * 24),
Percentage: 1,
},
},
}

target, err := doesUserQualifyForFeature(config, feature, user, nil)
require.NoError(t, err)
require.Equal(t, "61536f669c69b86cccc5f15e", target.Target.Id)

require.NotNil(t, feature)
feature.Configuration.Targets[0].Rollout = &Rollout{
Type: "gradual",
StartPercentage: 0,
StartDate: time.Now().Add(time.Hour * -24),
Stages: []RolloutStage{
{
Type: "linear",
Date: time.Now().Add(time.Hour * -1),
Percentage: 1,
},
},
}

target, err = doesUserQualifyForFeature(config, feature, user, nil)
require.NoError(t, err)
require.Equal(t, "61536f468fd67f0091982533", target.Target.Id)

}

func TestUserHashingBucketing_BucketingDistribution(t *testing.T) {
buckets := map[string]float64{
"var1": 0,
Expand Down
2 changes: 1 addition & 1 deletion bucketing/segmentation.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ func _checkNumberFilter(num float64, filterNums []float64, operator string) bool
}
return passesFilter
}

// replace filterNums.some() logic
someValue := false
for _, filterNum := range filterNums {
Expand Down
66 changes: 16 additions & 50 deletions bucketing/testdata/fixture_test_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -472,60 +472,18 @@
},
"variations": [
{
"_id": "6153553b8cf4e45e0464268d",
"name": "variation 1",
"key": "variation-1-key",
"variables": [
{
"_var": "614ef6ea475129459160721a",
"value": "scat"
},
{
"_var": "615356f120ed334a6054564c",
"value": "man"
},
{
"_var": "61538237b0a70b58ae6af71y",
"value": false
},
{
"_var": "61538237b0a70b58ae6af71s",
"value": 610.61
},
{
"_var": "61538237b0a70b58ae6af71q",
"value": "{\"hello\":\"world\",\"num\":610,\"bool\":true}"
}
]
},
{
"_id": "615357cf7e9ebdca58446ed0",
"name": "variation 2",
"key": "variation-2-key",
"_id": "615382338424cb11646d7667",
"name": "variation 1 aud 2",
"key": "variation-1-aud-2-key",
"variables": [
{
"_var": "615356f120ed334a6054564c",
"value": "YEEEEOWZA"
},
{
"_var": "61538237b0a70b58ae6af71y",
"value": false
"_var": "61538237b0a70b58ae6af71g",
"value": "Var 1 aud 2"
},
{
"_var": "61538237b0a70b58ae6af71s",
"value": 610.61
"_var": "61538237b0a70b58ae6af71h",
"value": "Var 1 aud 2"
},
{
"_var": "61538237b0a70b58ae6af71q",
"value": "{\"hello\":\"world\",\"num\":610,\"bool\":true}"
}
]
},
{
"_id": "615382338424cb11646d7667",
"name": "variation 1 aud 2",
"key": "variation-1-aud-2-key",
"variables": [
{
"_var": "61538237b0a70b58ae6af71f",
"value": "Var 1 aud 2"
Expand All @@ -544,6 +502,10 @@
{
"_var": "61538237b0a70b58ae6af71h",
"value": "multivar last"
},
{
"_var": "61538237b0a70b58ae6af71f",
"value": "Var 1 multivar"
}
]
},
Expand All @@ -559,6 +521,10 @@
{
"_var": "61538237b0a70b58ae6af71h",
"value": "multivar last unused"
},
{
"_var": "61538237b0a70b58ae6af71f",
"value": "Var 1 multivar"
}
]
}
Expand Down Expand Up @@ -720,4 +686,4 @@
"feature2.cool": 2621975932,
"feature2.hello": 4138596111
}
}
}
2 changes: 1 addition & 1 deletion event_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func (e *EventManager) FlushEvents() (err error) {
defer e.flushMutex.Unlock()

util.Debugf("Started flushing events")

defer func() {
if r := recover(); r != nil {
// get the stack trace and potentially log it here
Expand Down

0 comments on commit 12c0f18

Please sign in to comment.