diff --git a/testservice/go.mod b/testservice/go.mod index 574bc5aa..742f7d47 100644 --- a/testservice/go.mod +++ b/testservice/go.mod @@ -7,7 +7,7 @@ require ( github.com/aws/aws-sdk-go-v2/credentials v1.12.18 github.com/aws/aws-sdk-go-v2/service/dynamodb v1.16.4 github.com/gorilla/mux v1.8.0 - github.com/launchdarkly/go-sdk-common/v3 v3.5.0 + github.com/launchdarkly/go-sdk-common/v3 v3.5.1-0.20260707203913-381c033e045f github.com/launchdarkly/go-server-sdk-consul/v3 v3.0.2 github.com/launchdarkly/go-server-sdk-dynamodb/v4 v4.0.3 github.com/launchdarkly/go-server-sdk-redis-go-redis v1.1.2 @@ -31,6 +31,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/fatih/color v1.9.0 // indirect + github.com/fsnotify/fsnotify v1.4.7 // indirect github.com/google/uuid v1.1.1 // indirect github.com/gregjones/httpcache v0.0.0-20171119193500-2bcd89a1743f // indirect github.com/hashicorp/consul/api v1.12.0 // indirect @@ -45,9 +46,9 @@ require ( github.com/launchdarkly/ccache v1.1.0 // indirect github.com/launchdarkly/eventsource v1.10.0 // indirect github.com/launchdarkly/go-jsonstream/v3 v3.1.1 // indirect - github.com/launchdarkly/go-sdk-events/v3 v3.6.2 // indirect + github.com/launchdarkly/go-sdk-events/v3 v3.6.3-0.20260707205009-8af496ae2ab5 // indirect github.com/launchdarkly/go-semver v1.0.3 // indirect - github.com/launchdarkly/go-server-sdk-evaluation/v3 v3.0.1 // indirect + github.com/launchdarkly/go-server-sdk-evaluation/v3 v3.0.2-0.20260707205605-a8cc07261329 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.6 // indirect github.com/mattn/go-isatty v0.0.12 // indirect @@ -57,6 +58,8 @@ require ( github.com/redis/go-redis/v9 v9.0.2 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.38.0 // indirect + gopkg.in/ghodss/yaml.v1 v1.0.0 // indirect + gopkg.in/yaml.v2 v2.3.0 // indirect ) replace github.com/launchdarkly/go-server-sdk/v7 => ../ diff --git a/testservice/go.sum b/testservice/go.sum index ce85f8b9..2454f97c 100644 --- a/testservice/go.sum +++ b/testservice/go.sum @@ -48,6 +48,8 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cu github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= @@ -100,26 +102,30 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF github.com/karlseguin/expect v1.0.2-0.20190806010014-778a5f0c6003 h1:vJ0Snvo+SLMY72r5J4sEfkuE7AFbixEP2qRbEcum/wA= github.com/karlseguin/expect v1.0.2-0.20190806010014-778a5f0c6003/go.mod h1:zNBxMY8P21owkeogJELCLeHIt+voOSduHYTFUbwRAV8= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/launchdarkly/ccache v1.1.0 h1:voD1M+ZJXR3MREOKtBwgTF9hYHl1jg+vFKS/+VAkR2k= github.com/launchdarkly/ccache v1.1.0/go.mod h1:TlxzrlnzvYeXiLHmesMuvoZetu4Z97cV1SsdqqBJi1Q= github.com/launchdarkly/eventsource v1.10.0 h1:H9Tp6AfGu/G2qzBJC26iperrvwhzdbiA/gx7qE2nDFI= github.com/launchdarkly/eventsource v1.10.0/go.mod h1:J3oa50bPvJesZqNAJtb5btSIo5N6roDWhiAS3IpsKck= github.com/launchdarkly/go-jsonstream/v3 v3.1.1 h1:ugupp2eNtwVbr69KCdeUrm1vUf1/3ju4Wdliaob95uY= github.com/launchdarkly/go-jsonstream/v3 v3.1.1/go.mod h1:ZBjhKq8mhArCtqotGRGnteY6eXpNm1GaOdUSZHh+ZjM= -github.com/launchdarkly/go-sdk-common/v3 v3.5.0 h1:DsfTimg4BZO2hQPeeeEZYZVsP25pAWEdq/rKv/b7HJU= -github.com/launchdarkly/go-sdk-common/v3 v3.5.0/go.mod h1:6MNeeP8b2VtsM6I3TbShCHW/+tYh2c+p5dB+ilS69sg= -github.com/launchdarkly/go-sdk-events/v3 v3.6.2 h1:X5sxi1Hz5Cj8wOyXiNnJzCcCGiGIy9IOSEk31lCfDXM= -github.com/launchdarkly/go-sdk-events/v3 v3.6.2/go.mod h1:s86HRgbVAHjoQjQEOzgOB+ZKWlU4wwHAeDa/5N6MwO0= +github.com/launchdarkly/go-sdk-common/v3 v3.5.1-0.20260707203913-381c033e045f h1:wsrL79voFEPH70Dc6E6B9dnqWlS9nnwiKwHHw3SX7Fw= +github.com/launchdarkly/go-sdk-common/v3 v3.5.1-0.20260707203913-381c033e045f/go.mod h1:6MNeeP8b2VtsM6I3TbShCHW/+tYh2c+p5dB+ilS69sg= +github.com/launchdarkly/go-sdk-events/v3 v3.6.3-0.20260707205009-8af496ae2ab5 h1:19MHm77s549uaFl3iP/+g7T98FNQt1PF5sPITH93HKo= +github.com/launchdarkly/go-sdk-events/v3 v3.6.3-0.20260707205009-8af496ae2ab5/go.mod h1:s86HRgbVAHjoQjQEOzgOB+ZKWlU4wwHAeDa/5N6MwO0= github.com/launchdarkly/go-semver v1.0.3 h1:agIy/RN3SqeQDIfKkl+oFslEdeIs7pgsJBs3CdCcGQM= github.com/launchdarkly/go-semver v1.0.3/go.mod h1:xFmMwXba5Mb+3h72Z+VeSs9ahCvKo2QFUTHRNHVqR28= github.com/launchdarkly/go-server-sdk-consul/v3 v3.0.2 h1:iOW5uo9cARmLFyTA++AEnnzbrl4AYZVlTjNvMrcJc9k= github.com/launchdarkly/go-server-sdk-consul/v3 v3.0.2/go.mod h1:niVvmrHvqUm1ZpsO90A+7ujMN2i9wfEHjTlWwIeWag0= github.com/launchdarkly/go-server-sdk-dynamodb/v4 v4.0.3 h1:1BZ+BOQ63w9pYsJ0Tiey8zL+nEnIbs8qEjKGBKzo5KA= github.com/launchdarkly/go-server-sdk-dynamodb/v4 v4.0.3/go.mod h1:JNBcfcuLthOG8SL+f9QUQprbVdu7y8sYPugZ7Ck5p3U= -github.com/launchdarkly/go-server-sdk-evaluation/v3 v3.0.1 h1:rTgcYAFraGFj7sBMB2b7JCYCm0b9kph4FaMX02t4osQ= -github.com/launchdarkly/go-server-sdk-evaluation/v3 v3.0.1/go.mod h1:fPS5d+zOsgFnMunj+Ki6jjlZtFvo4h9iNbtNXxzYn58= +github.com/launchdarkly/go-server-sdk-evaluation/v3 v3.0.2-0.20260707205605-a8cc07261329 h1:+Jg/Xrqg5ZaOdagIHv386xVkm/EbjXWcZTn1h1DQPls= +github.com/launchdarkly/go-server-sdk-evaluation/v3 v3.0.2-0.20260707205605-a8cc07261329/go.mod h1:rDPT4v+kM13xg1hgTZBwiv3UEgArn8jJi+TIelyx36k= github.com/launchdarkly/go-server-sdk-redis-go-redis v1.1.2 h1:qaxHvxmDEtkVoek43PICqu1hI3h4J0x9HUR7KjYsRWE= github.com/launchdarkly/go-server-sdk-redis-go-redis v1.1.2/go.mod h1:MCHcQhcFu7VS4J4tP6Z3qP8JvP9j4f59r2oQx9WFONI= github.com/launchdarkly/go-test-helpers/v2 v2.3.2 h1:WX6qSzt7v8xz6d94nVcoil9ljuLTC/6OzQt0MhWYxsQ= @@ -161,6 +167,8 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/redis/go-redis/v9 v9.0.2 h1:BA426Zqe/7r56kCcvxYLWe1mkaz71LKF77GwgFzSxfE= github.com/redis/go-redis/v9 v9.0.2/go.mod h1:/xDTe9EF1LM61hek62Poq2nzQSGj0xSrEtEHbBQevps= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= @@ -210,6 +218,8 @@ golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/ghodss/yaml.v1 v1.0.0 h1:JlY4R6oVz+ZSvcDhVfNQ/k/8Xo6yb2s1PBhslPZPX4c= gopkg.in/ghodss/yaml.v1 v1.0.0/go.mod h1:HDvRMPQLqycKPs9nWLuzZWxsxRzISLCRORiDpBUOMqg= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/testservice/sdk_client_entity.go b/testservice/sdk_client_entity.go index 4d59b516..9920ea49 100644 --- a/testservice/sdk_client_entity.go +++ b/testservice/sdk_client_entity.go @@ -26,6 +26,7 @@ import ( "github.com/launchdarkly/go-server-sdk/v7/interfaces/flagstate" "github.com/launchdarkly/go-server-sdk/v7/ldcomponents" "github.com/launchdarkly/go-server-sdk/v7/ldhooks" + "github.com/launchdarkly/go-server-sdk/v7/ldoverrides" "github.com/launchdarkly/go-server-sdk/v7/subsystems" "github.com/launchdarkly/go-server-sdk/v7/testservice/servicedef" @@ -490,8 +491,14 @@ func makeSDKConfig(config servicedef.SDKConfigParams, sdkLog ldlog.Loggers) (ld. dataSystemBuilder.DataStore(builder, subsystems.DataStoreMode(config.DataSystem.StoreMode)) } + if config.Overrides != nil { + dataSystemBuilder.Overrides(makeOverridesConfig(config.Overrides)) + } + sdkLog.Debugf("Data system configuration: %+v", dataSystemBuilder) ret.DataSystem = dataSystemBuilder + } else if config.Overrides != nil { + return ret, errors.New("flag overrides require the data system to be configured") } else { if config.ServiceEndpoints != nil { ret.ServiceEndpoints.Streaming = config.ServiceEndpoints.Streaming @@ -649,6 +656,23 @@ func asJSON(value interface{}) string { return string(ret) } +func makeOverridesConfig(params *servicedef.SDKConfigOverridesParams) *ldoverrides.FileSourceBuilder { + builder := ldoverrides.FileSource().FilePaths(params.FilePaths...) + if params.DuplicateKeysHandling != nil { + builder.DuplicateKeysHandling(ldoverrides.DuplicateKeysHandling(*params.DuplicateKeysHandling)) + } + if params.Watch != nil { + builder.Watch(*params.Watch) + } + if params.Poll != nil { + builder.Poll(*params.Poll) + } + if params.PollIntervalMS != nil { + builder.PollInterval(time.Millisecond * time.Duration(*params.PollIntervalMS)) + } + return builder +} + func makeSynchronizerConfig(synchronizer servicedef.Synchronizer, configParams servicedef.SDKConfigParams, config *ld.Config) (subsystems.ComponentConfigurer[subsystems.DataSynchronizer], error) { if synchronizer.Polling != nil { if config.ServiceEndpoints.Polling == "" { diff --git a/testservice/service.go b/testservice/service.go index 589a6121..644fecb5 100644 --- a/testservice/service.go +++ b/testservice/service.go @@ -52,6 +52,7 @@ var capabilities = []string{ servicedef.CapabilityFlagValueChangeListeners, servicedef.CapabilityFDv1Fallback, servicedef.CapabilityInstanceID, + servicedef.CapabilityFlagOverrides, } // gets the specified environment variable, or the default if not set diff --git a/testservice/servicedef/sdk_config.go b/testservice/servicedef/sdk_config.go index d8d2716f..2239a17a 100644 --- a/testservice/servicedef/sdk_config.go +++ b/testservice/servicedef/sdk_config.go @@ -18,6 +18,16 @@ type SDKConfigParams struct { Hooks *SDKConfigHooksParams `json:"hooks,omitempty"` PersistentDataStore *SDKConfigPersistentDataStoreParams `json:"persistentDataStore,omitempty"` DataSystem *DataSystem `json:"dataSystem,omitempty"` + Overrides *SDKConfigOverridesParams `json:"overrides,omitempty"` +} + +// SDKConfigOverridesParams configures a file-based flag override source. +type SDKConfigOverridesParams struct { + FilePaths []string `json:"filePaths"` + DuplicateKeysHandling *string `json:"duplicateKeysHandling,omitempty"` + Watch *bool `json:"watch,omitempty"` + Poll *bool `json:"poll,omitempty"` + PollIntervalMS *int `json:"pollIntervalMs,omitempty"` } type SDKConfigServiceEndpointsParams struct { diff --git a/testservice/servicedef/service_params.go b/testservice/servicedef/service_params.go index b4639ae7..68eec675 100644 --- a/testservice/servicedef/service_params.go +++ b/testservice/servicedef/service_params.go @@ -33,6 +33,7 @@ const ( CapabilityFlagValueChangeListeners = "flag-value-change-listeners" CapabilityFDv1Fallback = "fdv1-fallback" CapabilityInstanceID = "instance-id" + CapabilityFlagOverrides = "flag-overrides" ) type StatusRep struct {