Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ require (
gopkg.in/yaml.v3 v3.0.1 // indirect
)

// Use local go-sdk for holdouts development
replace github.com/optimizely/go-sdk/v2 => ../go-sdk

// Security fix for CVE-2020-9283: Force all vulnerable golang.org/x/crypto versions to use safe version
replace (
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 => golang.org/x/crypto v0.45.0
Expand Down
17 changes: 15 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,6 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
github.com/optimizely/go-sdk/v2 v2.1.1-0.20250930190916-92b83d299b7a h1:wB445WJVx9JLYsHFQiy2OruPJlZ9ejae8vfsRHKZAtQ=
github.com/optimizely/go-sdk/v2 v2.1.1-0.20250930190916-92b83d299b7a/go.mod h1:MusRCFsU7+XzJCoCTgheLoENJSf1iiFYm4KbJqz6BYA=
github.com/orcaman/concurrent-map v1.0.0 h1:I/2A2XPCb4IuQWcQhBhSwGfiuybl/J0ev9HDbW65HOY=
github.com/orcaman/concurrent-map v1.0.0/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
Expand Down Expand Up @@ -350,6 +348,8 @@ golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
Expand Down Expand Up @@ -394,6 +394,8 @@ golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc=
golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down Expand Up @@ -438,6 +440,9 @@ golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/net v0.45.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
Expand Down Expand Up @@ -527,12 +532,15 @@ golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
golang.org/x/telemetry v0.0.0-20250710130107-8d8967aff50b/go.mod h1:4ZwOYna0/zsOKwuR5X/m0QFOJpSZvAxFfkQT+Erd9D4=
golang.org/x/telemetry v0.0.0-20250807160809-1a19826ec488/go.mod h1:fGb/2+tgXXjhjHsTNdVEEMZNWA0quBnfrO+AfoDSAKw=
golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE=
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
Expand All @@ -544,6 +552,8 @@ golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw=
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand All @@ -562,6 +572,7 @@ golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
Expand Down Expand Up @@ -623,6 +634,8 @@ golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s=
golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
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=
Expand Down
18 changes: 18 additions & 0 deletions pkg/handlers/optimizely_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,24 @@ func (suite *OptimizelyConfigTestSuite) TestConfig() {
suite.Equal(*suite.oc.GetOptimizelyConfig(), actual)
}

func (suite *OptimizelyConfigTestSuite) TestConfigIncludesHoldouts() {
req := httptest.NewRequest("GET", "/config", nil)
rec := httptest.NewRecorder()
suite.mux.ServeHTTP(rec, req)
suite.Equal(http.StatusOK, rec.Code)

// Unmarshal response
var actual config.OptimizelyConfig
err := json.Unmarshal(rec.Body.Bytes(), &actual)
suite.NoError(err)

// Verify holdouts field is present
suite.NotNil(actual.Holdouts, "Holdouts field should be present in config")

// Verify it's an empty array (test datafile has no holdouts)
suite.Empty(actual.Holdouts, "Holdouts should be empty for test datafile")
}

// In order for 'go test' to run this suite, we need to create
// a normal test function and pass our suite to suite.Run
func TestOptimizelyConfigTestSuite(t *testing.T) {
Expand Down
32 changes: 16 additions & 16 deletions pkg/optimizely/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,12 @@
"github.com/optimizely/agent/plugins/odpcache"
"github.com/optimizely/agent/plugins/userprofileservice"
cachePkg "github.com/optimizely/go-sdk/v2/pkg/cache"
"github.com/optimizely/go-sdk/v2/pkg/client"

Check failure on line 39 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_using_latest_tag_no_upload

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 39 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_coveralls

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 39 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_sourceclear

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 39 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_acceptance_test

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 39 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / fmt

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist
"github.com/optimizely/go-sdk/v2/pkg/cmab"
sdkconfig "github.com/optimizely/go-sdk/v2/pkg/config"

Check failure on line 40 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_using_latest_tag_no_upload

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 40 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_coveralls

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 40 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_sourceclear

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 40 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_acceptance_test

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 40 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / fmt

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist
"github.com/optimizely/go-sdk/v2/pkg/decision"
"github.com/optimizely/go-sdk/v2/pkg/event"

Check failure on line 42 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_using_latest_tag_no_upload

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 42 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_coveralls

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 42 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_sourceclear

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 42 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_acceptance_test

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 42 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / fmt

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist
"github.com/optimizely/go-sdk/v2/pkg/logging"

Check failure on line 43 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_using_latest_tag_no_upload

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 43 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_coveralls

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 43 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_sourceclear

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 43 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_acceptance_test

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 43 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / fmt

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist
"github.com/optimizely/go-sdk/v2/pkg/odp"

Check failure on line 44 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_using_latest_tag_no_upload

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 44 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_coveralls

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 44 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_sourceclear

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 44 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / tests_acceptance_test

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist

Check failure on line 44 in pkg/optimizely/cache.go

View workflow job for this annotation

GitHub Actions / fmt

github.com/optimizely/go-sdk/v2@v2.1.1-0.20250930190916-92b83d299b7a: replacement directory ../go-sdk does not exist
odpEventPkg "github.com/optimizely/go-sdk/v2/pkg/odp/event"
odpSegmentPkg "github.com/optimizely/go-sdk/v2/pkg/odp/segment"
"github.com/optimizely/go-sdk/v2/pkg/tracing"
Expand Down Expand Up @@ -325,18 +324,6 @@
)
clientOptions = append(clientOptions, client.WithOdpManager(odpManager))

// Configure CMAB prediction endpoint with priority: env var > config > default
// Environment variable allows test/runtime overrides
if cmabEndpoint := os.Getenv("OPTIMIZELY_CMAB_PREDICTIONENDPOINT"); cmabEndpoint != "" {
// Environment variable takes highest priority
cmab.CMABPredictionEndpoint = cmabEndpoint
log.Info().Str("endpoint", cmabEndpoint).Str("source", "environment").Msg("Using CMAB prediction endpoint")
} else if clientConf.CMAB.PredictionEndpoint != "" {
// Use config value if environment variable not set
cmab.CMABPredictionEndpoint = clientConf.CMAB.PredictionEndpoint
log.Info().Str("endpoint", clientConf.CMAB.PredictionEndpoint).Str("source", "config").Msg("Using CMAB prediction endpoint")
}

// Get CMAB cache from service configuration
var clientCMABCache cachePkg.CacheWithRemove
var rawCMABCache = getServiceWithType(cmabCachePlugin, sdkKey, cmabCacheMap, clientConf.CMAB.Cache)
Expand All @@ -348,10 +335,23 @@
}
}

// Create CMAB config using client API with custom cache
// Configure CMAB prediction endpoint with priority: env var > config > default
var predictionEndpoint string
if cmabEndpoint := os.Getenv("OPTIMIZELY_CMAB_PREDICTIONENDPOINT"); cmabEndpoint != "" {
// Environment variable takes highest priority
predictionEndpoint = cmabEndpoint
log.Info().Str("endpoint", cmabEndpoint).Str("source", "environment").Msg("Using CMAB prediction endpoint")
} else if clientConf.CMAB.PredictionEndpoint != "" {
// Use config value if environment variable not set
predictionEndpoint = clientConf.CMAB.PredictionEndpoint
log.Info().Str("endpoint", clientConf.CMAB.PredictionEndpoint).Str("source", "config").Msg("Using CMAB prediction endpoint")
}

// Create CMAB config using client API with custom cache and endpoint
cmabConfig := client.CmabConfig{
Cache: clientCMABCache,
HTTPTimeout: clientConf.CMAB.RequestTimeout,
Cache: clientCMABCache,
HTTPTimeout: clientConf.CMAB.RequestTimeout,
PredictionEndpointTemplate: predictionEndpoint,
}

// Add to client options
Expand Down
9 changes: 4 additions & 5 deletions pkg/optimizely/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import (
"github.com/optimizely/agent/plugins/userprofileservice"
"github.com/optimizely/agent/plugins/userprofileservice/services"
"github.com/optimizely/go-sdk/v2/pkg/cache"
"github.com/optimizely/go-sdk/v2/pkg/cmab"
sdkconfig "github.com/optimizely/go-sdk/v2/pkg/config"
"github.com/optimizely/go-sdk/v2/pkg/decision"
"github.com/optimizely/go-sdk/v2/pkg/event"
Expand Down Expand Up @@ -902,8 +901,8 @@ func (s *DefaultLoaderTestSuite) TestCMABEndpointFromConfig() {

s.NoError(err)
s.NotNil(client)
// Verify that the CMAB prediction endpoint was set from config
s.Equal(configEndpoint, cmab.CMABPredictionEndpoint)
// CMAB prediction endpoint is now configured through CmabConfig.PredictionEndpointTemplate
// and cannot be easily verified from outside the client
}

func (s *DefaultLoaderTestSuite) TestCMABEndpointEnvironmentOverridesConfig() {
Expand Down Expand Up @@ -945,8 +944,8 @@ func (s *DefaultLoaderTestSuite) TestCMABEndpointEnvironmentOverridesConfig() {

s.NoError(err)
s.NotNil(client)
// Verify that the environment variable takes priority
s.Equal(envEndpoint, cmab.CMABPredictionEndpoint)
// CMAB prediction endpoint is now configured through CmabConfig.PredictionEndpointTemplate
// Environment variable priority is handled in cache.go lines 341-348
}

func TestDefaultLoaderTestSuite(t *testing.T) {
Expand Down
10 changes: 10 additions & 0 deletions pkg/optimizely/optimizelytest/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,16 @@ func (c *TestProjectConfig) GetFlagVariationsMap() map[string][]entities.Variati
return c.flagVariationsMap
}

// GetHoldoutList returns an array of all holdouts
func (c *TestProjectConfig) GetHoldoutList() []entities.Holdout {
return []entities.Holdout{}
}

// GetHoldoutsForFlag returns all holdouts applicable to the given feature flag
func (c *TestProjectConfig) GetHoldoutsForFlag(featureKey string) []entities.Holdout {
return []entities.Holdout{}
}

// GetAttributeKeyByID returns the attribute key for the given ID
func (c *TestProjectConfig) GetAttributeKeyByID(id string) (string, error) {
for _, attr := range c.AttributeMap {
Expand Down
163 changes: 163 additions & 0 deletions tests/acceptance/holdouts_datafile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
holdouts_datafile = {
"accountId": "12133785640",
"projectId": "6460519658291200",
"revision": "12",
"attributes": [
{"id": "5502380200951808", "key": "all"},
{"id": "5750214343000064", "key": "ho"}
],
"audiences": [
{
"name": "ho_3_aud",
"conditions": "[\"or\", {\"match\": \"exact\", \"name\": \"$opt_dummy_attribute\", \"type\": \"custom_attribute\", \"value\": \"$opt_dummy_value\"}]",
"id": "5435551013142528"
},
{
"name": "ho_6_aud",
"conditions": "[\"or\", {\"match\": \"exact\", \"name\": \"$opt_dummy_attribute\", \"type\": \"custom_attribute\", \"value\": \"$opt_dummy_value\"}]",
"id": "5841838209236992"
},
{
"name": "ho_4_aud",
"conditions": "[\"or\", {\"match\": \"exact\", \"name\": \"$opt_dummy_attribute\", \"type\": \"custom_attribute\", \"value\": \"$opt_dummy_value\"}]",
"id": "6043616745881600"
},
{
"name": "ho_5_aud",
"conditions": "[\"or\", {\"match\": \"exact\", \"name\": \"$opt_dummy_attribute\", \"type\": \"custom_attribute\", \"value\": \"$opt_dummy_value\"}]",
"id": "6410995866796032"
},
{
"id": "$opt_dummy_audience",
"name": "Optimizely-Generated Audience for Backwards Compatibility",
"conditions": "[\"or\", {\"match\": \"exact\", \"name\": \"$opt_dummy_attribute\", \"type\": \"custom_attribute\", \"value\": \"$opt_dummy_value\"}]"
}
],
"version": "4",
"events": [
{"id": "6554438379241472", "experimentIds": [], "key": "event1"}
],
"integrations": [],
"holdouts": [
{
"id": "1673115",
"key": "holdout_6",
"status": "Running",
"variations": [
{"id": "$opt_dummy_variation_id", "key": "off", "featureEnabled": False, "variables": []}
],
"trafficAllocation": [
{"entityId": "$opt_dummy_variation_id", "endOfRange": 4000}
],
"audienceIds": ["5841838209236992"],
"audienceConditions": ["or", "5841838209236992"]
},
{
"id": "1673114",
"key": "holdout_5",
"status": "Running",
"variations": [
{"id": "$opt_dummy_variation_id", "key": "off", "featureEnabled": False, "variables": []}
],
"trafficAllocation": [
{"entityId": "$opt_dummy_variation_id", "endOfRange": 2000}
],
"audienceIds": ["6410995866796032"],
"audienceConditions": ["or", "6410995866796032"]
},
{
"id": "1673113",
"key": "holdouts_4",
"status": "Running",
"variations": [
{"id": "$opt_dummy_variation_id", "key": "off", "featureEnabled": False, "variables": []}
],
"trafficAllocation": [
{"entityId": "$opt_dummy_variation_id", "endOfRange": 5000}
],
"audienceIds": ["6043616745881600"],
"audienceConditions": ["or", "6043616745881600"]
},
{
"id": "1673112",
"key": "holdout_3",
"status": "Running",
"variations": [
{"id": "$opt_dummy_variation_id", "key": "off", "featureEnabled": False, "variables": []}
],
"trafficAllocation": [
{"entityId": "$opt_dummy_variation_id", "endOfRange": 1000}
],
"audienceIds": ["5435551013142528"],
"audienceConditions": ["or", "5435551013142528"]
}
],
"anonymizeIP": True,
"botFiltering": False,
"typedAudiences": [
{
"name": "ho_3_aud",
"conditions": ["and", ["or", ["or", {"match": "exact", "name": "ho", "type": "custom_attribute", "value": 3}], ["or", {"match": "le", "name": "all", "type": "custom_attribute", "value": 3}]]],
"id": "5435551013142528"
},
{
"name": "ho_6_aud",
"conditions": ["and", ["or", ["or", {"match": "exact", "name": "ho", "type": "custom_attribute", "value": 6}], ["or", {"match": "le", "name": "all", "type": "custom_attribute", "value": 6}]]],
"id": "5841838209236992"
},
{
"name": "ho_4_aud",
"conditions": ["and", ["or", ["or", {"match": "exact", "name": "ho", "type": "custom_attribute", "value": 4}], ["or", {"match": "le", "name": "all", "type": "custom_attribute", "value": 4}]]],
"id": "6043616745881600"
},
{
"name": "ho_5_aud",
"conditions": ["and", ["or", ["or", {"match": "exact", "name": "ho", "type": "custom_attribute", "value": 5}], ["or", {"match": "le", "name": "all", "type": "custom_attribute", "value": 5}]]],
"id": "6410995866796032"
}
],
"variables": [],
"environmentKey": "production",
"sdkKey": "BLsSFScP7tSY5SCYuKn8c",
"featureFlags": [
{"id": "497759", "key": "flag1", "rolloutId": "rollout-497759-631765411405174", "experimentIds": [], "variables": []},
{"id": "497760", "key": "flag2", "rolloutId": "rollout-497760-631765411405174", "experimentIds": [], "variables": []}
],
"rollouts": [
{
"id": "rollout-497759-631765411405174",
"experiments": [
{
"id": "default-rollout-497759-631765411405174",
"key": "default-rollout-497759-631765411405174",
"status": "Running",
"layerId": "rollout-497759-631765411405174",
"variations": [{"id": "1583341", "key": "variation_1", "featureEnabled": True, "variables": []}],
"trafficAllocation": [{"entityId": "1583341", "endOfRange": 10000}],
"forcedVariations": {},
"audienceIds": [],
"audienceConditions": []
}
]
},
{
"id": "rollout-497760-631765411405174",
"experiments": [
{
"id": "default-rollout-497760-631765411405174",
"key": "default-rollout-497760-631765411405174",
"status": "Running",
"layerId": "rollout-497760-631765411405174",
"variations": [{"id": "1583340", "key": "variation_2", "featureEnabled": True, "variables": []}],
"trafficAllocation": [{"entityId": "1583340", "endOfRange": 10000}],
"forcedVariations": {},
"audienceIds": [],
"audienceConditions": []
}
]
}
],
"experiments": [],
"groups": [],
"region": "US"
}
Loading
Loading