From e368b91c6d634eb51b6f496269ccd572c42cba0b Mon Sep 17 00:00:00 2001 From: drei Date: Sun, 24 Sep 2023 23:26:38 -0300 Subject: [PATCH 01/11] Add Source field to NewFeatureEvent --- cmd/relayproxy/controller/collect_eval_data.go | 1 + exporter/data_exporter_test.go | 15 ++++++++------- exporter/feature_event.go | 9 ++++++++- exporter/feature_event_test.go | 9 ++++++--- variation.go | 6 ++++-- 5 files changed, 27 insertions(+), 13 deletions(-) diff --git a/cmd/relayproxy/controller/collect_eval_data.go b/cmd/relayproxy/controller/collect_eval_data.go index a065157bfcb..46bb29aa1eb 100644 --- a/cmd/relayproxy/controller/collect_eval_data.go +++ b/cmd/relayproxy/controller/collect_eval_data.go @@ -47,6 +47,7 @@ func (h *collectEvalData) Handler(c echo.Context) error { } for _, event := range reqBody.Events { + event.Source = "PROVIDER_CACHE" h.goFF.CollectEventData(event) } diff --git a/exporter/data_exporter_test.go b/exporter/data_exporter_test.go index a2be270d7ef..70288a3ee15 100644 --- a/exporter/data_exporter_test.go +++ b/exporter/data_exporter_test.go @@ -3,13 +3,14 @@ package exporter_test import ( "context" "errors" - "github.com/thomaspoignant/go-feature-flag/exporter" - "github.com/thomaspoignant/go-feature-flag/ffcontext" "log" "os" "testing" "time" + "github.com/thomaspoignant/go-feature-flag/exporter" + "github.com/thomaspoignant/go-feature-flag/ffcontext" + "github.com/stretchr/testify/assert" "github.com/thomaspoignant/go-feature-flag/testutils/mock" @@ -26,7 +27,7 @@ func TestDataExporterScheduler_flushWithTime(t *testing.T) { inputEvents := []exporter.FeatureEvent{ exporter.NewFeatureEvent( ffcontext.NewEvaluationContextBuilder("ABCD").AddCustom("anonymous", true).Build(), "random-key", - "YO", "defaultVar", false, ""), + "YO", "defaultVar", false, "", "SERVER"), } for _, event := range inputEvents { @@ -48,7 +49,7 @@ func TestDataExporterScheduler_flushWithNumberOfEvents(t *testing.T) { for i := 0; i <= 100; i++ { inputEvents = append(inputEvents, exporter.NewFeatureEvent( ffcontext.NewEvaluationContextBuilder("ABCD").AddCustom("anonymous", true).Build(), - "random-key", "YO", "defaultVar", false, "")) + "random-key", "YO", "defaultVar", false, "", "SERVER")) } for _, event := range inputEvents { dc.AddEvent(event) @@ -67,7 +68,7 @@ func TestDataExporterScheduler_defaultFlush(t *testing.T) { for i := 0; i <= 100000; i++ { inputEvents = append(inputEvents, exporter.NewFeatureEvent( ffcontext.NewEvaluationContextBuilder("ABCD").AddCustom("anonymous", true).Build(), - "random-key", "YO", "defaultVar", false, "")) + "random-key", "YO", "defaultVar", false, "", "SERVER")) } for _, event := range inputEvents { dc.AddEvent(event) @@ -92,7 +93,7 @@ func TestDataExporterScheduler_exporterReturnError(t *testing.T) { for i := 0; i <= 200; i++ { inputEvents = append(inputEvents, exporter.NewFeatureEvent( ffcontext.NewEvaluationContextBuilder("ABCD").AddCustom("anonymous", true).Build(), - "random-key", "YO", "defaultVar", false, "")) + "random-key", "YO", "defaultVar", false, "", "SERVER")) } for _, event := range inputEvents { dc.AddEvent(event) @@ -114,7 +115,7 @@ func TestDataExporterScheduler_nonBulkExporter(t *testing.T) { for i := 0; i < 100; i++ { inputEvents = append(inputEvents, exporter.NewFeatureEvent( ffcontext.NewEvaluationContextBuilder("ABCD").AddCustom("anonymous", true).Build(), - "random-key", "YO", "defaultVar", false, "")) + "random-key", "YO", "defaultVar", false, "", "SERVER")) } for _, event := range inputEvents { dc.AddEvent(event) diff --git a/exporter/feature_event.go b/exporter/feature_event.go index 2a073f15abf..abfff6a5c0a 100644 --- a/exporter/feature_event.go +++ b/exporter/feature_event.go @@ -2,8 +2,9 @@ package exporter import ( "encoding/json" - "github.com/thomaspoignant/go-feature-flag/ffcontext" "time" + + "github.com/thomaspoignant/go-feature-flag/ffcontext" ) func NewFeatureEvent( @@ -13,6 +14,7 @@ func NewFeatureEvent( variation string, failed bool, version string, + source string, ) FeatureEvent { contextKind := "user" if ctx.IsAnonymous() { @@ -29,6 +31,7 @@ func NewFeatureEvent( Value: value, Default: failed, Version: version, + Source: source, } } @@ -68,6 +71,10 @@ type FeatureEvent struct { // Version contains the version of the flag. If the field is omitted for the flag in the configuration file // the default version will be 0. Version string `json:"version" example:"v1.0.0" parquet:"name=version, type=BYTE_ARRAY, convertedtype=UTF8"` + + // Source indicates where the event generated. + // This is set to SERVER when the event was evaluated in the relay-proxy and PROVIDER_CACHE when it is evaluated from the cache. + Source string `json:"source" example:"SERVER" parquet:"name=source, type=BYTE_ARRAY, convertedtype=UTF8"` } // MarshalInterface marshals all interface type fields in FeatureEvent into JSON-encoded string. diff --git a/exporter/feature_event_test.go b/exporter/feature_event_test.go index c10e50e762b..2732c08c8ea 100644 --- a/exporter/feature_event_test.go +++ b/exporter/feature_event_test.go @@ -1,10 +1,11 @@ package exporter_test import ( - "github.com/thomaspoignant/go-feature-flag/ffcontext" "testing" "time" + "github.com/thomaspoignant/go-feature-flag/ffcontext" + "github.com/stretchr/testify/assert" "github.com/thomaspoignant/go-feature-flag/exporter" ) @@ -17,6 +18,7 @@ func TestNewFeatureEvent(t *testing.T) { variation string failed bool version string + source string } tests := []struct { name string @@ -32,16 +34,17 @@ func TestNewFeatureEvent(t *testing.T) { variation: "Default", failed: false, version: "", + source: "SERVER", }, want: exporter.FeatureEvent{ Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: time.Now().Unix(), Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - assert.Equalf(t, tt.want, exporter.NewFeatureEvent(tt.args.user, tt.args.flagKey, tt.args.value, tt.args.variation, tt.args.failed, tt.args.version), "NewFeatureEvent(%v, %v, %v, %v, %v, %v)", tt.args.user, tt.args.flagKey, tt.args.value, tt.args.variation, tt.args.failed, tt.args.version) + assert.Equalf(t, tt.want, exporter.NewFeatureEvent(tt.args.user, tt.args.flagKey, tt.args.value, tt.args.variation, tt.args.failed, tt.args.version, tt.args.source), "NewFeatureEvent(%v, %v, %v, %v, %v, %v, %V)", tt.args.user, tt.args.flagKey, tt.args.value, tt.args.variation, tt.args.failed, tt.args.version, tt.args.source) }) } } diff --git a/variation.go b/variation.go index 327a97ad44c..22805c7060b 100644 --- a/variation.go +++ b/variation.go @@ -2,9 +2,10 @@ package ffclient import ( "fmt" + "time" + "github.com/thomaspoignant/go-feature-flag/exporter" "github.com/thomaspoignant/go-feature-flag/ffcontext" - "time" "github.com/thomaspoignant/go-feature-flag/internal/flag" "github.com/thomaspoignant/go-feature-flag/internal/flagstate" @@ -360,7 +361,8 @@ func notifyVariation[T model.JSONType]( result model.VariationResult[T], ) { if result.TrackEvents { - event := exporter.NewFeatureEvent(ctx, flagKey, result.Value, result.VariationType, result.Failed, result.Version) + event := exporter.NewFeatureEvent(ctx, flagKey, result.Value, result.VariationType, result.Failed, result.Version, + "SERVER") g.CollectEventData(event) } } From 838ca2b929babba65c2973d75af904a76d15873d Mon Sep 17 00:00:00 2001 From: drei Date: Mon, 25 Sep 2023 13:39:48 -0300 Subject: [PATCH 02/11] fix small typo --- exporter/logsexporter/exporter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exporter/logsexporter/exporter.go b/exporter/logsexporter/exporter.go index fb0d8cc29ee..d4834e6bfe3 100644 --- a/exporter/logsexporter/exporter.go +++ b/exporter/logsexporter/exporter.go @@ -33,7 +33,7 @@ type Exporter struct { // Export is saving a collection of events in a file. func (f *Exporter) Export(_ context.Context, logger *log.Logger, featureEvents []exporter.FeatureEvent) error { f.initTemplates.Do(func() { - // Remove bellow after deprecation of Format + // Remove below after deprecation of Format if f.LogFormat == "" && f.Format != "" { f.LogFormat = f.Format } From efc21dcd6c5b4a2f1a752577cdc12057f9dc6f61 Mon Sep 17 00:00:00 2001 From: drei Date: Mon, 25 Sep 2023 15:55:37 -0300 Subject: [PATCH 03/11] Update tests and comments to include the Source field --- README.md | 3 ++- cmd/relayproxy/config/config.go | 2 +- .../valid_collected_data.json | 2 +- examples/data_export_file/main.go | 15 ++++++++------- .../data_export_googlecloudstorage/main.go | 15 ++++++++------- examples/data_export_s3/main.go | 19 ++++++++++--------- exporter/common.go | 2 +- exporter/fileexporter/exporter.go | 3 ++- exporter/fileexporter/exporter_test.go | 2 +- .../fileexporter/testdata/all_default.json | 4 ++-- .../testdata/custom_file_name.json | 4 ++-- feature_flag.go | 9 +++++---- 12 files changed, 43 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 714257faedc..8869a0a6ed3 100644 --- a/README.md +++ b/README.md @@ -560,7 +560,8 @@ It represents individual flag evaluations and is considered "full fidelity" even "key": "test-flag", "variation": "Default", "value": false, - "default": false + "default": false, + "source": "SERVER" } ``` The format of the data is [described in the documentation](https://gofeatureflag.org/docs/). diff --git a/cmd/relayproxy/config/config.go b/cmd/relayproxy/config/config.go index 225a95d3406..a6d1bd9ae3a 100644 --- a/cmd/relayproxy/config/config.go +++ b/cmd/relayproxy/config/config.go @@ -45,7 +45,7 @@ var DefaultExporter = struct { LogFormat: "[{{ .FormattedDate}}] user=\"{{ .UserKey}}\", flag=\"{{ .Key}}\", value=\"{{ .Value}}\"", FileName: "flag-variation-{{ .Hostname}}-{{ .Timestamp}}.{{ .Format}}", CsvFormat: "{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};" + - "{{ .Value}};{{ .Default}}\n", + "{{ .Value}};{{ .Default}};{{ .Source}}\n", FlushInterval: 60000 * time.Millisecond, MaxEventInMemory: 100000, ParquetCompressionCodec: parquet.CompressionCodec_SNAPPY.String(), diff --git a/cmd/relayproxy/testdata/controller/collect_eval_data/valid_collected_data.json b/cmd/relayproxy/testdata/controller/collect_eval_data/valid_collected_data.json index 7c98528f070..e5fb25016ea 100644 --- a/cmd/relayproxy/testdata/controller/collect_eval_data/valid_collected_data.json +++ b/cmd/relayproxy/testdata/controller/collect_eval_data/valid_collected_data.json @@ -1 +1 @@ -{"kind":"feature","contextKind":"user","userKey":"94a25909-20d8-40cc-8500-fee99b569345","creationDate":1680246000011,"key":"my-feature-flag","variation":"admin-variation","value":"string","default":false,"version":"v1.0.0"} +{"kind":"feature","contextKind":"user","userKey":"94a25909-20d8-40cc-8500-fee99b569345","creationDate":1680246000011,"key":"my-feature-flag","variation":"admin-variation","value":"string","default":false,"version":"v1.0.0","source":"PROVIDER_CACHE"} diff --git a/examples/data_export_file/main.go b/examples/data_export_file/main.go index 94fcbcf5457..f8c93832d3e 100644 --- a/examples/data_export_file/main.go +++ b/examples/data_export_file/main.go @@ -2,11 +2,12 @@ package main import ( "context" - "github.com/thomaspoignant/go-feature-flag/ffcontext" "log" "os" "time" + "github.com/thomaspoignant/go-feature-flag/ffcontext" + "github.com/thomaspoignant/go-feature-flag/exporter/fileexporter" "github.com/thomaspoignant/go-feature-flag/retriever/fileretriever" @@ -60,13 +61,13 @@ func main() { The output will be something like that: flag-variation-EXAMPLE-.json: - {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"new-admin-access","variation":"True","value":true,"default":false} - {"kind":"feature","contextKind":"user","userKey":"332460b9-a8aa-4f7a-bc5d-9cc33632df9a","creationDate":1618234129,"key":"new-admin-access","variation":"False","value":false,"default":false} - {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"unknown-flag","variation":"SdkDefault","value":"defaultValue","default":true} - {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"unknown-flag-2","variation":"SdkDefault","value":{"test":"toto"},"default":true} + {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"new-admin-access","variation":"True","value":true,"default":false,"source":"SERVER"} + {"kind":"feature","contextKind":"user","userKey":"332460b9-a8aa-4f7a-bc5d-9cc33632df9a","creationDate":1618234129,"key":"new-admin-access","variation":"False","value":false,"default":false,"source":"SERVER"} + {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"unknown-flag","variation":"SdkDefault","value":"defaultValue","default":true,"source":"SERVER"} + {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"unknown-flag-2","variation":"SdkDefault","value":{"test":"toto"},"default":true,"source":"SERVER"} ---- flag-variation-EXAMPLE-.json: - {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234131,"key":"new-admin-access","variation":"True","value":true,"default":false} - {"kind":"feature","contextKind":"user","userKey":"332460b9-a8aa-4f7a-bc5d-9cc33632df9a","creationDate":1618234131,"key":"new-admin-access","variation":"False","value":false,"default":false} + {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234131,"key":"new-admin-access","variation":"True","value":true,"default":false,"source":"SERVER"} + {"kind":"feature","contextKind":"user","userKey":"332460b9-a8aa-4f7a-bc5d-9cc33632df9a","creationDate":1618234131,"key":"new-admin-access","variation":"False","value":false,"default":false,"source":"SERVER"} */ } diff --git a/examples/data_export_googlecloudstorage/main.go b/examples/data_export_googlecloudstorage/main.go index 2c3df8ec68e..1180ea85ab7 100644 --- a/examples/data_export_googlecloudstorage/main.go +++ b/examples/data_export_googlecloudstorage/main.go @@ -2,11 +2,12 @@ package main import ( "context" - "github.com/thomaspoignant/go-feature-flag/ffcontext" "log" "os" "time" + "github.com/thomaspoignant/go-feature-flag/ffcontext" + "github.com/thomaspoignant/go-feature-flag/exporter/gcstorageexporter" "github.com/thomaspoignant/go-feature-flag/retriever/fileretriever" "google.golang.org/api/option" @@ -69,13 +70,13 @@ func main() { /* The content of those files should looks like: /go-feature-flag/variations/flag-variation-EXAMPLE-.json: - {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"new-admin-access","variation":"True","value":true,"default":false} - {"kind":"feature","contextKind":"user","userKey":"332460b9-a8aa-4f7a-bc5d-9cc33632df9a","creationDate":1618234129,"key":"new-admin-access","variation":"False","value":false,"default":false} - {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"unknown-flag","variation":"SdkDefault","value":"defaultValue","default":true} - {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"unknown-flag-2","variation":"SdkDefault","value":{"test":"toto"},"default":true} + {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"new-admin-access","variation":"True","value":true,"default":false,"source":"SERVER"} + {"kind":"feature","contextKind":"user","userKey":"332460b9-a8aa-4f7a-bc5d-9cc33632df9a","creationDate":1618234129,"key":"new-admin-access","variation":"False","value":false,"default":false,"source":"SERVER"} + {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"unknown-flag","variation":"SdkDefault","value":"defaultValue","default":true,"source":"SERVER"} + {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"unknown-flag-2","variation":"SdkDefault","value":{"test":"toto"},"default":true,"source":"SERVER"} ---- /go-feature-flag/variations/flag-variation-EXAMPLE-.json: - {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234131,"key":"new-admin-access","variation":"True","value":true,"default":false} - {"kind":"feature","contextKind":"user","userKey":"332460b9-a8aa-4f7a-bc5d-9cc33632df9a","creationDate":1618234131,"key":"new-admin-access","variation":"False","value":false,"default":false} + {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234131,"key":"new-admin-access","variation":"True","value":true,"default":false,"source":"SERVER"} + {"kind":"feature","contextKind":"user","userKey":"332460b9-a8aa-4f7a-bc5d-9cc33632df9a","creationDate":1618234131,"key":"new-admin-access","variation":"False","value":false,"default":false,"source":"SERVER"} */ } diff --git a/examples/data_export_s3/main.go b/examples/data_export_s3/main.go index f308bea23c7..69ad67bcf7d 100644 --- a/examples/data_export_s3/main.go +++ b/examples/data_export_s3/main.go @@ -2,14 +2,15 @@ package main import ( "context" + "log" + "os" + "time" + "github.com/aws/aws-sdk-go-v2/config" ffclient "github.com/thomaspoignant/go-feature-flag" "github.com/thomaspoignant/go-feature-flag/exporter/s3exporterv2" "github.com/thomaspoignant/go-feature-flag/ffcontext" "github.com/thomaspoignant/go-feature-flag/retriever/fileretriever" - "log" - "os" - "time" ) func main() { @@ -68,13 +69,13 @@ func main() { /* The content of those files should looks like: /go-feature-flag/variations/flag-variation-EXAMPLE-.json: - {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"new-admin-access","variation":"True","value":true,"default":false} - {"kind":"feature","contextKind":"user","userKey":"332460b9-a8aa-4f7a-bc5d-9cc33632df9a","creationDate":1618234129,"key":"new-admin-access","variation":"False","value":false,"default":false} - {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"unknown-flag","variation":"SdkDefault","value":"defaultValue","default":true} - {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"unknown-flag-2","variation":"SdkDefault","value":{"test":"toto"},"default":true} + {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"new-admin-access","variation":"True","value":true,"default":false,"source":"SERVER"} + {"kind":"feature","contextKind":"user","userKey":"332460b9-a8aa-4f7a-bc5d-9cc33632df9a","creationDate":1618234129,"key":"new-admin-access","variation":"False","value":false,"default":false,"source":"SERVER"} + {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"unknown-flag","variation":"SdkDefault","value":"defaultValue","default":true,"source":"SERVER"} + {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234129,"key":"unknown-flag-2","variation":"SdkDefault","value":{"test":"toto"},"default":true,"source":"SERVER"} ---- /go-feature-flag/variations/flag-variation-EXAMPLE-.json: - {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234131,"key":"new-admin-access","variation":"True","value":true,"default":false} - {"kind":"feature","contextKind":"user","userKey":"332460b9-a8aa-4f7a-bc5d-9cc33632df9a","creationDate":1618234131,"key":"new-admin-access","variation":"False","value":false,"default":false} + {"kind":"feature","contextKind":"anonymousUser","userKey":"aea2fdc1-b9a0-417a-b707-0c9083de68e3","creationDate":1618234131,"key":"new-admin-access","variation":"True","value":true,"default":false,"source":"SERVER"} + {"kind":"feature","contextKind":"user","userKey":"332460b9-a8aa-4f7a-bc5d-9cc33632df9a","creationDate":1618234131,"key":"new-admin-access","variation":"False","value":false,"default":false,"source":"SERVER"} */ } diff --git a/exporter/common.go b/exporter/common.go index cdbece99bd1..152173f2c89 100644 --- a/exporter/common.go +++ b/exporter/common.go @@ -11,7 +11,7 @@ import ( ) const DefaultCsvTemplate = "{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};" + - "{{ .Value}};{{ .Default}}\n" + "{{ .Value}};{{ .Default}};{{ .Source}}\n" const DefaultFilenameTemplate = "flag-variation-{{ .Hostname}}-{{ .Timestamp}}.{{ .Format}}" // ParseTemplate is parsing the template given by the config or use the default template diff --git a/exporter/fileexporter/exporter.go b/exporter/fileexporter/exporter.go index 973c44ad269..42feaf052d9 100644 --- a/exporter/fileexporter/exporter.go +++ b/exporter/fileexporter/exporter.go @@ -38,7 +38,8 @@ type Exporter struct { // You can decide which fields you want in your CSV line with a go-template syntax, // please check exporter/feature_event.go to see what are the fields available. // Default: - // {{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}}\n + // {{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}}; + // {{ .Default}};{{ .Source}}\n CsvTemplate string // ParquetCompressionCodec is the parquet compression codec for better space efficiency. diff --git a/exporter/fileexporter/exporter_test.go b/exporter/fileexporter/exporter_test.go index 4d9758dae96..2ab174f0ed0 100644 --- a/exporter/fileexporter/exporter_test.go +++ b/exporter/fileexporter/exporter_test.go @@ -52,7 +52,7 @@ func TestFile_Export(t *testing.T) { }, { Kind: "feature", ContextKind: "anonymousUser", UserKey: "EFGH", CreationDate: 1617970701, Key: "random-key", - Variation: "Default", Value: "YO2", Default: false, Version: "127", + Variation: "Default", Value: "YO2", Default: false, Version: "127", Source: "SERVER", }, }, }, diff --git a/exporter/fileexporter/testdata/all_default.json b/exporter/fileexporter/testdata/all_default.json index 99ab92ad5bd..aa837a30f1f 100644 --- a/exporter/fileexporter/testdata/all_default.json +++ b/exporter/fileexporter/testdata/all_default.json @@ -1,2 +1,2 @@ -{"kind":"feature","contextKind":"anonymousUser","userKey":"ABCD","creationDate":1617970547,"key":"random-key","variation":"Default","value":"YO","default":false,"version":""} -{"kind":"feature","contextKind":"anonymousUser","userKey":"EFGH","creationDate":1617970701,"key":"random-key","variation":"Default","value":"YO2","default":false,"version":"127"} +{"kind":"feature","contextKind":"anonymousUser","userKey":"ABCD","creationDate":1617970547,"key":"random-key","variation":"Default","value":"YO","default":false,"version":"","source":"SERVER"} +{"kind":"feature","contextKind":"anonymousUser","userKey":"EFGH","creationDate":1617970701,"key":"random-key","variation":"Default","value":"YO2","default":false,"version":"127","source":"SERVER"} diff --git a/exporter/fileexporter/testdata/custom_file_name.json b/exporter/fileexporter/testdata/custom_file_name.json index 891251dd748..8b58af310c6 100644 --- a/exporter/fileexporter/testdata/custom_file_name.json +++ b/exporter/fileexporter/testdata/custom_file_name.json @@ -1,2 +1,2 @@ -{"kind":"feature","contextKind":"anonymousUser","userKey":"ABCD","creationDate":1617970547,"key":"random-key","variation":"Default","value":"YO","default":false,"version":""} -{"kind":"feature","contextKind":"anonymousUser","userKey":"EFGH","creationDate":1617970701,"key":"random-key","variation":"Default","value":"YO2","default":false,"version":""} +{"kind":"feature","contextKind":"anonymousUser","userKey":"ABCD","creationDate":1617970547,"key":"random-key","variation":"Default","value":"YO","default":false,"version":"","source":"SERVER"} +{"kind":"feature","contextKind":"anonymousUser","userKey":"EFGH","creationDate":1617970701,"key":"random-key","variation":"Default","value":"YO2","default":false,"version":"","SOURCE":"SERVER"} diff --git a/feature_flag.go b/feature_flag.go index 61eb86a37b0..fc215243709 100644 --- a/feature_flag.go +++ b/feature_flag.go @@ -3,13 +3,14 @@ package ffclient import ( "context" "fmt" + "log" + "sync" + "time" + "github.com/thomaspoignant/go-feature-flag/exporter" "github.com/thomaspoignant/go-feature-flag/internal/dto" "github.com/thomaspoignant/go-feature-flag/retriever" "github.com/thomaspoignant/go-feature-flag/utils/fflog" - "log" - "sync" - "time" "github.com/thomaspoignant/go-feature-flag/notifier/logsnotifier" @@ -41,7 +42,7 @@ func Close() { } // GoFeatureFlag is the main object of the library -// it contains the cache, the config and the update. +// it contains the cache, the config, the updater and the exporter. type GoFeatureFlag struct { cache cache.Manager config Config From 5906990b2c31627010648d629d76984f7618d2a6 Mon Sep 17 00:00:00 2001 From: drei Date: Mon, 25 Sep 2023 16:21:52 -0300 Subject: [PATCH 04/11] Update documentation to include the Source field on the FeatureEvent --- exporter/feature_event.go | 2 +- website/docs/go_module/data_collection/file.md | 2 +- .../docs/go_module/data_collection/google_cloud_storage.md | 2 +- website/docs/go_module/data_collection/index.md | 6 ++++-- website/docs/go_module/data_collection/s3.md | 6 +++--- website/docs/go_module/data_collection/webhook.md | 3 ++- website/docs/relay_proxy/configure_relay_proxy.md | 6 +++--- 7 files changed, 15 insertions(+), 12 deletions(-) diff --git a/exporter/feature_event.go b/exporter/feature_event.go index abfff6a5c0a..08a68ed2524 100644 --- a/exporter/feature_event.go +++ b/exporter/feature_event.go @@ -72,7 +72,7 @@ type FeatureEvent struct { // the default version will be 0. Version string `json:"version" example:"v1.0.0" parquet:"name=version, type=BYTE_ARRAY, convertedtype=UTF8"` - // Source indicates where the event generated. + // Source indicates where the event was generated. // This is set to SERVER when the event was evaluated in the relay-proxy and PROVIDER_CACHE when it is evaluated from the cache. Source string `json:"source" example:"SERVER" parquet:"name=source, type=BYTE_ARRAY, convertedtype=UTF8"` } diff --git a/website/docs/go_module/data_collection/file.md b/website/docs/go_module/data_collection/file.md index 9bcf78aeb1a..91216c49947 100644 --- a/website/docs/go_module/data_collection/file.md +++ b/website/docs/go_module/data_collection/file.md @@ -18,7 +18,7 @@ ffclient.Config{ OutputDir: "/output-data/", Format: "csv", FileName: "flag-variation-{{ .Hostname}}-{{ .Timestamp}}.{{ .Format}}", - CsvTemplate: "{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}}\n" + CsvTemplate: "{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}};{{ .Source}}\n" }, }, // ... diff --git a/website/docs/go_module/data_collection/google_cloud_storage.md b/website/docs/go_module/data_collection/google_cloud_storage.md index 0e1821453c8..14bacd54f85 100644 --- a/website/docs/go_module/data_collection/google_cloud_storage.md +++ b/website/docs/go_module/data_collection/google_cloud_storage.md @@ -36,7 +36,7 @@ ffclient.Config{ | Field | Description | |---------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `Bucket ` | Name of your Google Cloud Storage Bucket. | -| `CsvTemplate` | *(optional)* CsvTemplate is used if your output format is CSV. This field will be ignored if you are using another format than CSV. You can decide which fields you want in your CSV line with a go-template syntax, please check [internal/exporter/feature_event.go](https://github.com/thomaspoignant/go-feature-flag/blob/main/internal/exporter/feature_event.go) to see what are the fields available.
**Default:** `{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}}\n` | +| `CsvTemplate` | *(optional)* CsvTemplate is used if your output format is CSV. This field will be ignored if you are using another format than CSV. You can decide which fields you want in your CSV line with a go-template syntax, please check [internal/exporter/feature_event.go](https://github.com/thomaspoignant/go-feature-flag/blob/main/internal/exporter/feature_event.go) to see what are the fields available.
**Default:** `{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}};{{ .Source}}\n` | | `Filename` | *(optional)* Filename is the name of your output file. You can use a templated config to define the name of your exported files.
Available replacement are `{{ .Hostname}}`, `{{ .Timestamp}`} and `{{ .Format}}`
Default: `flag-variation-{{ .Hostname}}-{{ .Timestamp}}.{{ .Format}}` | | `Format` | *(optional)* Format is the output format you want in your exported file. Available format are **`JSON`**, **`CSV`**, **`Parquet`**. *(Default: `JSON`)* | | `Options` | *(optional)* An instance of `option.ClientOption` that configures your access to Google Cloud.
Check [this documentation for more info](https://cloud.google.com/docs/authentication). | diff --git a/website/docs/go_module/data_collection/index.md b/website/docs/go_module/data_collection/index.md index f2df3328876..e137f5fed79 100644 --- a/website/docs/go_module/data_collection/index.md +++ b/website/docs/go_module/data_collection/index.md @@ -31,7 +31,8 @@ It represents individual flag evaluations and are considered "full fidelity" eve "key": "test-flag", "variation": "Default", "value": false, - "default": false + "default": false, + "source": "SERVER" } ``` @@ -44,8 +45,9 @@ It represents individual flag evaluations and are considered "full fidelity" eve | **`userKey`** | The key of the user object used in a feature flag evaluation. | | **`creationDate`** | When the feature flag was requested at Unix epoch time in milliseconds. | | **`key`** | The key of the feature flag requested. | -| **`variation`** | The variation of the flag requested. Available values are:
**True**: if the flag was evaluated to True
**False**: if the flag was evaluated to False
**Dafault**: if the flag was evaluated to Default
**SdkDefault**: if something wrong happened and the SDK default value was used. | +| **`variation`** | The variation of the flag requested. Available values are:
**True**: if the flag was evaluated to True
**False**: if the flag was evaluated to False
**Default**: if the flag was evaluated to Default
**SdkDefault**: if something wrong happened and the SDK default value was used. | | **`value`** | The value of the feature flag returned by feature flag evaluation. | +| **`source`** | Where the event was generated. This is set to SERVER when the event was evaluated in the relay-proxy and PROVIDER_CACHE when it is evaluated from the cache. | **`default`** | (Optional) This value is set to true if feature flag evaluation failed, in which case the value returned was the default value passed to variation. | Events are collected and send in bulk to avoid spamming your exporter *(see details in [how to configure data export](#how-to-configure-data-export)*) diff --git a/website/docs/go_module/data_collection/s3.md b/website/docs/go_module/data_collection/s3.md index 0898a87ef7d..fddd3a6f102 100644 --- a/website/docs/go_module/data_collection/s3.md +++ b/website/docs/go_module/data_collection/s3.md @@ -27,7 +27,7 @@ ffclient.Config{ Exporter: &s3exporterv2.Exporter{ Format: "csv", FileName: "flag-variation-{{ .Hostname}}-{{ .Timestamp}}.{{ .Format}}", - CsvTemplate: "{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}}\n", + CsvTemplate: "{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}};{{ .Source}}\n", Bucket: "my-bucket", S3Path: "/go-feature-flag/variations/", Filename: "flag-variation-{{ .Timestamp}}.{{ .Format}}", @@ -43,8 +43,8 @@ ffclient.Config{ |---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `Bucket ` | Name of your S3 Bucket. | | `AwsConfig ` | An instance of `aws.Config` that configure your access to AWS *(see [this documentation for more info](https://aws.github.io/aws-sdk-go-v2/docs/configuring-sdk/))*. | -| `CsvTemplate` | *(optional)* CsvTemplate is used if your output format is CSV. This field will be ignored if you are using another format than CSV. You can decide which fields you want in your CSV line with a go-template syntax, please check [internal/exporter/feature_event.go](https://github.com/thomaspoignant/go-feature-flag/blob/main/internal/exporter/feature_event.go) to see what are the fields available.
**Default:** `{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}}\n` | -| `Filename` | *(optional)* Filename is the name of your output file. You can use a templated config to define the name of your exported files.
Available replacement are `{{ .Hostname}}`, `{{ .Timestamp}`} and `{{ .Format}}`
Default: `flag-variation-{{ .Hostname}}-{{ .Timestamp}}.{{ .Format}}` | +| `CsvTemplate` | *(optional)* CsvTemplate is used if your output format is CSV. This field will be ignored if you are using another format than CSV. You can decide which fields you want in your CSV line with a go-template syntax, please check [internal/exporter/feature_event.go](https://github.com/thomaspoignant/go-feature-flag/blob/main/internal/exporter/feature_event.go) to see what are the fields available.
**Default:** `{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}};{{ .Source}}\n` | +| `Filename` | *(optional)* Filename is the name of your output file. You can use a templated config to define the name of your exported files.
Available replacement are `{{ .Hostname}}`, `{{ .Timestamp}}` and `{{ .Format}}`
Default: `flag-variation-{{ .Hostname}}-{{ .Timestamp}}.{{ .Format}}` | | `Format` | *(optional)* Format is the output format you want in your exported file. Available format are **`JSON`**, **`CSV`**, **`Parquet`**. *(Default: `JSON`)* | | `S3Path ` | *(optional)* The location of the directory in S3. | | `ParquetCompressionCodec` | *(optional)* ParquetCompressionCodec is the parquet compression codec for better space efficiency. [Available options](https://github.com/apache/parquet-format/blob/master/Compression.md) *(Default: `SNAPPY`)* |` diff --git a/website/docs/go_module/data_collection/webhook.md b/website/docs/go_module/data_collection/webhook.md index 4578f85712d..b6491c0b135 100644 --- a/website/docs/go_module/data_collection/webhook.md +++ b/website/docs/go_module/data_collection/webhook.md @@ -57,7 +57,8 @@ If you have configured a webhook, a `POST` request will be sent to the `Endpoint "key": "test-flag", "variation": "Default", "value": false, - "default": false + "default": false, + "source": "SERVER" }, // ... ] diff --git a/website/docs/relay_proxy/configure_relay_proxy.md b/website/docs/relay_proxy/configure_relay_proxy.md index fa7448b3b91..f95afa428a4 100644 --- a/website/docs/relay_proxy/configure_relay_proxy.md +++ b/website/docs/relay_proxy/configure_relay_proxy.md @@ -153,7 +153,7 @@ _Note that relay proxy is only supporting this while running inside the kubernet | `maxEventInMemory` | int | `100000` | If we hit that limit we will call the webhook. | | `format` | string | `JSON` | Format is the output format you want in your exported file. Available format: `JSON`, `CSV`, `Parquet`. | | `filename` | string | `flag-variation-{{ .Hostname}}-{{ .Timestamp}}.{{ .Format}}` | You can use a templated config to define the name of your exported files. Available replacement are `{{ .Hostname}}`, `{{ .Timestamp}}` and `{{ .Format}` | -| `csvTemplate` | string | `{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}}\n` | CsvTemplate is used if your output format is CSV.
This field will be ignored if you are using another format than CSV.
You can decide which fields you want in your CSV line with a go-template syntax, please check [`internal/exporter/feature_event.go`](https://github.com/thomaspoignant/go-feature-flag/blob/main/internal/exporter/feature_event.go) to see what are the fields available. |` +| `csvTemplate` | string | `{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}};{{ .Source}}\n` | CsvTemplate is used if your output format is CSV.
This field will be ignored if you are using another format than CSV.
You can decide which fields you want in your CSV line with a go-template syntax, please check [`internal/exporter/feature_event.go`](https://github.com/thomaspoignant/go-feature-flag/blob/main/internal/exporter/feature_event.go) to see what are the fields available. |` | `parquetCompressionCodec` | string | `SNAPPY` | ParquetCompressionCodec is the parquet compression codec for better space efficiency. [Available options](https://github.com/apache/parquet-format/blob/master/Compression.md) |` @@ -176,7 +176,7 @@ _Note that relay proxy is only supporting this while running inside the kubernet | `maxEventInMemory` | int | `100000` | If we hit that limit we will call the webhook. | | `format` | string | `JSON` | Format is the output format you want in your exported file. Available format: `JSON`, `CSV`, `Parquet`. | | `filename` | string | `flag-variation-{{ .Hostname}}-{{ .Timestamp}}.{{ .Format}}` | You can use a templated config to define the name of your exported files. Available replacement are `{{ .Hostname}}`, `{{ .Timestamp}}` and `{{ .Format}` | -| `csvTemplate` | string | `{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}}\n` | CsvTemplate is used if your output format is CSV.
This field will be ignored if you are using another format than CSV.
You can decide which fields you want in your CSV line with a go-template syntax, please check [`internal/exporter/feature_event.go`](https://github.com/thomaspoignant/go-feature-flag/blob/main/internal/exporter/feature_event.go) to see what are the fields available. |` +| `csvTemplate` | string | `{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}};{{ .Source}}\n` | CsvTemplate is used if your output format is CSV.
This field will be ignored if you are using another format than CSV.
You can decide which fields you want in your CSV line with a go-template syntax, please check [`internal/exporter/feature_event.go`](https://github.com/thomaspoignant/go-feature-flag/blob/main/internal/exporter/feature_event.go) to see what are the fields available. |` | `path` | string | **bucket root level** | The location of the directory in S3. | | `parquetCompressionCodec` | string | `SNAPPY` | ParquetCompressionCodec is the parquet compression codec for better space efficiency. [Available options](https://github.com/apache/parquet-format/blob/master/Compression.md) |` @@ -190,7 +190,7 @@ _Note that relay proxy is only supporting this while running inside the kubernet | `maxEventInMemory` | int | `100000` | If we hit that limit we will call the webhook. | | `format` | string | `JSON` | Format is the output format you want in your exported file. Available format: `JSON`, `CSV`, `Parquet`. | | `filename` | string | `flag-variation-{{ .Hostname}}-{{ .Timestamp}}.{{ .Format}}` | You can use a templated config to define the name of your exported files. Available replacement are `{{ .Hostname}}`, `{{ .Timestamp}}` and `{{ .Format}` | -| `csvTemplate` | string | `{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}}\n` | CsvTemplate is used if your output format is CSV.
This field will be ignored if you are using another format than CSV.
You can decide which fields you want in your CSV line with a go-template syntax, please check [`internal/exporter/feature_event.go`](https://github.com/thomaspoignant/go-feature-flag/blob/main/internal/exporter/feature_event.go) to see what are the fields available. |` +| `csvTemplate` | string | `{{ .Kind}};{{ .ContextKind}};{{ .UserKey}};{{ .CreationDate}};{{ .Key}};{{ .Variation}};{{ .Value}};{{ .Default}};{{ .Source}}\n` | CsvTemplate is used if your output format is CSV.
This field will be ignored if you are using another format than CSV.
You can decide which fields you want in your CSV line with a go-template syntax, please check [`internal/exporter/feature_event.go`](https://github.com/thomaspoignant/go-feature-flag/blob/main/internal/exporter/feature_event.go) to see what are the fields available. |` | `path` | string | **bucket root level** | The location of the directory in S3. | | `parquetCompressionCodec` | string | `SNAPPY` | ParquetCompressionCodec is the parquet compression codec for better space efficiency. [Available options](https://github.com/apache/parquet-format/blob/master/Compression.md) |` From dc8af91463fb873c73b675302aa6d9b271e48b07 Mon Sep 17 00:00:00 2001 From: drei Date: Mon, 25 Sep 2023 16:31:16 -0300 Subject: [PATCH 05/11] Fix typos --- website/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/README.md b/website/README.md index 6e08eb1b292..74491b97b32 100644 --- a/website/README.md +++ b/website/README.md @@ -10,16 +10,16 @@ You will need to have **nodejs** installed in your machine to work with the docu Your can start locally the website. 1. Open a terminal and go to the root project of this repository. -2. Launch the command bellow, it will install the dependencies and run the local server for the documentation. +2. Launch the command below, it will install the dependencies and run the local server for the documentation. ```shell make watch-doc ``` -3. You can now access to the documentation directly in your browser: [http://localhost:3000/](http://localhost:3000/). +3. You can now access the documentation directly in your browser: [http://localhost:3000/](http://localhost:3000/). ## Build the documentation 1. Open a terminal and go to the root project of this repository. -2. Launch the command bellow, it will install the dependencies and build the documentation. +2. Launch the command below, it will install the dependencies and build the documentation. ```shell make build-doc ``` From 570260f5776b66fd5758f2c708f1f5acafd9d5b4 Mon Sep 17 00:00:00 2001 From: drei Date: Mon, 25 Sep 2023 17:12:10 -0300 Subject: [PATCH 06/11] Update webhook exporter tests to add the Source field --- exporter/webhookexporter/exporter_test.go | 22 +++++++++---------- .../testdata/valid_with_signature.json | 6 +++-- .../testdata/valid_without_signature.json | 6 +++-- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/exporter/webhookexporter/exporter_test.go b/exporter/webhookexporter/exporter_test.go index c85d7cd46ac..330e98a6362 100644 --- a/exporter/webhookexporter/exporter_test.go +++ b/exporter/webhookexporter/exporter_test.go @@ -62,11 +62,11 @@ func TestWebhook_Export(t *testing.T) { featureEvents: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, { Kind: "feature", ContextKind: "anonymousUser", UserKey: "EFGH", CreationDate: 1617970701, Key: "random-key", - Variation: "Default", Value: "YO2", Default: false, Version: "127", + Variation: "Default", Value: "YO2", Default: false, Version: "127", Source: "SERVER", }, }, }, @@ -89,17 +89,17 @@ func TestWebhook_Export(t *testing.T) { featureEvents: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, { Kind: "feature", ContextKind: "anonymousUser", UserKey: "EFGH", CreationDate: 1617970701, Key: "random-key", - Variation: "Default", Value: "YO2", Default: false, Version: "127", + Variation: "Default", Value: "YO2", Default: false, Version: "127", Source: "SERVER", }, }, }, expected: expected{ bodyFilePath: "./testdata/valid_with_signature.json", - signHeader: "sha256=0c504fe37d423ff0a80e4dc29b93c18c2d1438a5387f36d8e6491e77fb5e70d4", + signHeader: "sha256=f1f9766836d4e513035986c035ee9f091b895709be47a802b5840467007e1ec0", }, wantErr: false, }, @@ -116,11 +116,11 @@ func TestWebhook_Export(t *testing.T) { featureEvents: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, { Kind: "feature", ContextKind: "anonymousUser", UserKey: "EFGH", CreationDate: 1617970701, Key: "random-key", - Variation: "Default", Value: "YO2", Default: false, + Variation: "Default", Value: "YO2", Default: false, Source: "SERVER", }, }, }, @@ -139,11 +139,11 @@ func TestWebhook_Export(t *testing.T) { featureEvents: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, { Kind: "feature", ContextKind: "anonymousUser", UserKey: "EFGH", CreationDate: 1617970701, Key: "random-key", - Variation: "Default", Value: "YO2", Default: false, + Variation: "Default", Value: "YO2", Default: false, Source: "SERVER", }, }, }, @@ -162,11 +162,11 @@ func TestWebhook_Export(t *testing.T) { featureEvents: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, { Kind: "feature", ContextKind: "anonymousUser", UserKey: "EFGH", CreationDate: 1617970701, Key: "random-key", - Variation: "Default", Value: "YO2", Default: false, Version: "127", + Variation: "Default", Value: "YO2", Default: false, Version: "127", Source: "SERVER", }, }, }, diff --git a/exporter/webhookexporter/testdata/valid_with_signature.json b/exporter/webhookexporter/testdata/valid_with_signature.json index 6467446841e..cf706280a9b 100644 --- a/exporter/webhookexporter/testdata/valid_with_signature.json +++ b/exporter/webhookexporter/testdata/valid_with_signature.json @@ -12,7 +12,8 @@ "variation": "Default", "value": "YO", "default": false, - "version": "" + "version": "", + "source": "SERVER" }, { "kind": "feature", @@ -23,7 +24,8 @@ "variation": "Default", "value": "YO2", "default": false, - "version": "127" + "version": "127", + "source": "SERVER" } ] } diff --git a/exporter/webhookexporter/testdata/valid_without_signature.json b/exporter/webhookexporter/testdata/valid_without_signature.json index 6467446841e..cf706280a9b 100644 --- a/exporter/webhookexporter/testdata/valid_without_signature.json +++ b/exporter/webhookexporter/testdata/valid_without_signature.json @@ -12,7 +12,8 @@ "variation": "Default", "value": "YO", "default": false, - "version": "" + "version": "", + "source": "SERVER" }, { "kind": "feature", @@ -23,7 +24,8 @@ "variation": "Default", "value": "YO2", "default": false, - "version": "127" + "version": "127", + "source": "SERVER" } ] } From 99c8f7725d6ca344cdf08d7944eabdf62a3b6ba1 Mon Sep 17 00:00:00 2001 From: drei Date: Mon, 25 Sep 2023 19:04:21 -0300 Subject: [PATCH 07/11] Update tests to include Source field on FeatureEvent --- exporter/common_test.go | 8 ++-- exporter/fileexporter/exporter_test.go | 40 ++++++++++--------- .../fileexporter/testdata/all_default.csv | 4 +- .../testdata/custom_file_name.json | 2 +- exporter/s3exporter/exporter_test.go | 18 ++++----- exporter/s3exporter/testdata/all_default.csv | 2 +- exporter/s3exporter/testdata/all_default.json | 2 +- exporter/s3exporterv2/exporter_test.go | 21 +++++----- .../s3exporterv2/testdata/all_default.csv | 2 +- .../s3exporterv2/testdata/all_default.json | 2 +- 10 files changed, 52 insertions(+), 49 deletions(-) diff --git a/exporter/common_test.go b/exporter/common_test.go index 7ff9cb7b65c..5ec0d759306 100644 --- a/exporter/common_test.go +++ b/exporter/common_test.go @@ -133,10 +133,10 @@ func TestFormatEventInCSV(t *testing.T) { csvTemplate: exporter.ParseTemplate("exporterExample", exporter.DefaultCsvTemplate, exporter.DefaultCsvTemplate), event: exporter.FeatureEvent{ Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, - want: "feature;anonymousUser;ABCD;1617970547;random-key;Default;YO;false\n", + want: "feature;anonymousUser;ABCD;1617970547;random-key;Default;YO;false;SERVER\n", wantErr: assert.NoError, }, } @@ -165,9 +165,9 @@ func TestFormatEventInJSON(t *testing.T) { name: "valid", args: args{event: exporter.FeatureEvent{ Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }}, - want: "{\"kind\":\"feature\",\"contextKind\":\"anonymousUser\",\"userKey\":\"ABCD\",\"creationDate\":1617970547,\"key\":\"random-key\",\"variation\":\"Default\",\"value\":\"YO\",\"default\":false,\"version\":\"\"}\n", + want: "{\"kind\":\"feature\",\"contextKind\":\"anonymousUser\",\"userKey\":\"ABCD\",\"creationDate\":1617970547,\"key\":\"random-key\",\"variation\":\"Default\",\"value\":\"YO\",\"default\":false,\"version\":\"\",\"source\":\"SERVER\"}\n", wantErr: assert.NoError, }, } diff --git a/exporter/fileexporter/exporter_test.go b/exporter/fileexporter/exporter_test.go index 2ab174f0ed0..f0cb2db346d 100644 --- a/exporter/fileexporter/exporter_test.go +++ b/exporter/fileexporter/exporter_test.go @@ -48,7 +48,7 @@ func TestFile_Export(t *testing.T) { featureEvents: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, { Kind: "feature", ContextKind: "anonymousUser", UserKey: "EFGH", CreationDate: 1617970701, Key: "random-key", @@ -71,11 +71,11 @@ func TestFile_Export(t *testing.T) { featureEvents: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, { Kind: "feature", ContextKind: "anonymousUser", UserKey: "EFGH", CreationDate: 1617970701, Key: "random-key", - Variation: "Default", Value: "YO2", Default: false, + Variation: "Default", Value: "YO2", Default: false, Source: "SERVER", }, }, }, @@ -95,11 +95,11 @@ func TestFile_Export(t *testing.T) { featureEvents: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, { Kind: "feature", ContextKind: "anonymousUser", UserKey: "EFGH", CreationDate: 1617970701, Key: "random-key", - Variation: "Default", Value: "YO2", Default: false, Version: "127", + Variation: "Default", Value: "YO2", Default: false, Version: "127", Source: "SERVER", }, }, }, @@ -108,11 +108,11 @@ func TestFile_Export(t *testing.T) { featureEvents: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: `"YO"`, Default: false, + Variation: "Default", Value: `"YO"`, Default: false, Source: "SERVER", }, { Kind: "feature", ContextKind: "anonymousUser", UserKey: "EFGH", CreationDate: 1617970701, Key: "random-key", - Variation: "Default", Value: `"YO2"`, Default: false, Version: "127", + Variation: "Default", Value: `"YO2"`, Default: false, Version: "127", Source: "SERVER", }, }, }, @@ -128,11 +128,11 @@ func TestFile_Export(t *testing.T) { featureEvents: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, { Kind: "feature", ContextKind: "anonymousUser", UserKey: "EFGH", CreationDate: 1617970701, Key: "random-key", - Variation: "Default", Value: "YO2", Default: false, + Variation: "Default", Value: "YO2", Default: false, Source: "SERVER", }, }, }, @@ -164,6 +164,7 @@ func TestFile_Export(t *testing.T) { "int": 1, }, Default: false, + Source: "SERVER", }, }, }, @@ -179,6 +180,7 @@ func TestFile_Export(t *testing.T) { Variation: "Default", Value: `{"bool":true,"float":1.23,"int":1,"string":"string"}`, Default: false, + Source: "SERVER", }, }, }, @@ -194,11 +196,11 @@ func TestFile_Export(t *testing.T) { featureEvents: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, { Kind: "feature", ContextKind: "anonymousUser", UserKey: "EFGH", CreationDate: 1617970701, Key: "random-key", - Variation: "Default", Value: "YO2", Default: false, + Variation: "Default", Value: "YO2", Default: false, Source: "SERVER", }, }, }, @@ -217,11 +219,11 @@ func TestFile_Export(t *testing.T) { featureEvents: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, { Kind: "feature", ContextKind: "anonymousUser", UserKey: "EFGH", CreationDate: 1617970701, Key: "random-key", - Variation: "Default", Value: "YO2", Default: false, Version: "127", + Variation: "Default", Value: "YO2", Default: false, Version: "127", Source: "SERVER", }, }, }, @@ -240,11 +242,11 @@ func TestFile_Export(t *testing.T) { featureEvents: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, { Kind: "feature", ContextKind: "anonymousUser", UserKey: "EFGH", CreationDate: 1617970701, Key: "random-key", - Variation: "Default", Value: "YO2", Default: false, + Variation: "Default", Value: "YO2", Default: false, Source: "SERVER", }, }, }, @@ -259,11 +261,11 @@ func TestFile_Export(t *testing.T) { featureEvents: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, { Kind: "feature", ContextKind: "anonymousUser", UserKey: "EFGH", CreationDate: 1617970701, Key: "random-key", - Variation: "Default", Value: "YO2", Default: false, + Variation: "Default", Value: "YO2", Default: false, Source: "SERVER", }, }, }, @@ -279,11 +281,11 @@ func TestFile_Export(t *testing.T) { featureEvents: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, { Kind: "feature", ContextKind: "anonymousUser", UserKey: "EFGH", CreationDate: 1617970701, Key: "random-key", - Variation: "Default", Value: "YO2", Default: false, + Variation: "Default", Value: "YO2", Default: false, Source: "SERVER", }, }, }, diff --git a/exporter/fileexporter/testdata/all_default.csv b/exporter/fileexporter/testdata/all_default.csv index 9541fdf0895..501ba4f8bad 100644 --- a/exporter/fileexporter/testdata/all_default.csv +++ b/exporter/fileexporter/testdata/all_default.csv @@ -1,2 +1,2 @@ -feature;anonymousUser;ABCD;1617970547;random-key;Default;YO;false -feature;anonymousUser;EFGH;1617970701;random-key;Default;YO2;false +feature;anonymousUser;ABCD;1617970547;random-key;Default;YO;false;SERVER +feature;anonymousUser;EFGH;1617970701;random-key;Default;YO2;false;SERVER diff --git a/exporter/fileexporter/testdata/custom_file_name.json b/exporter/fileexporter/testdata/custom_file_name.json index 8b58af310c6..fe6e945e07d 100644 --- a/exporter/fileexporter/testdata/custom_file_name.json +++ b/exporter/fileexporter/testdata/custom_file_name.json @@ -1,2 +1,2 @@ {"kind":"feature","contextKind":"anonymousUser","userKey":"ABCD","creationDate":1617970547,"key":"random-key","variation":"Default","value":"YO","default":false,"version":"","source":"SERVER"} -{"kind":"feature","contextKind":"anonymousUser","userKey":"EFGH","creationDate":1617970701,"key":"random-key","variation":"Default","value":"YO2","default":false,"version":"","SOURCE":"SERVER"} +{"kind":"feature","contextKind":"anonymousUser","userKey":"EFGH","creationDate":1617970701,"key":"random-key","variation":"Default","value":"YO2","default":false,"version":"","source":"SERVER"} diff --git a/exporter/s3exporter/exporter_test.go b/exporter/s3exporter/exporter_test.go index f3985c270e7..5f887bfeaa6 100644 --- a/exporter/s3exporter/exporter_test.go +++ b/exporter/s3exporter/exporter_test.go @@ -41,7 +41,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, expectedFile: "./testdata/all_default.json", @@ -56,7 +56,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, expectedFile: "./testdata/all_default.json", @@ -71,7 +71,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, expectedFile: "./testdata/all_default.csv", @@ -87,7 +87,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, expectedFile: "./testdata/custom_csv_format.csv", @@ -103,7 +103,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, expectedFile: "./testdata/all_default.json", @@ -118,7 +118,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, expectedFile: "./testdata/all_default.json", @@ -132,7 +132,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, wantErr: true, @@ -146,7 +146,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, wantErr: true, @@ -160,7 +160,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, wantErr: true, diff --git a/exporter/s3exporter/testdata/all_default.csv b/exporter/s3exporter/testdata/all_default.csv index db122b68d71..60f91161919 100644 --- a/exporter/s3exporter/testdata/all_default.csv +++ b/exporter/s3exporter/testdata/all_default.csv @@ -1 +1 @@ -feature;anonymousUser;ABCD;1617970547;random-key;Default;YO;false +feature;anonymousUser;ABCD;1617970547;random-key;Default;YO;false;SERVER diff --git a/exporter/s3exporter/testdata/all_default.json b/exporter/s3exporter/testdata/all_default.json index 9e702153e2e..851a24887d6 100644 --- a/exporter/s3exporter/testdata/all_default.json +++ b/exporter/s3exporter/testdata/all_default.json @@ -1 +1 @@ -{"kind":"feature","contextKind":"anonymousUser","userKey":"ABCD","creationDate":1617970547,"key":"random-key","variation":"Default","value":"YO","default":false,"version":""} +{"kind":"feature","contextKind":"anonymousUser","userKey":"ABCD","creationDate":1617970547,"key":"random-key","variation":"Default","value":"YO","default":false,"version":"","source":"SERVER"} diff --git a/exporter/s3exporterv2/exporter_test.go b/exporter/s3exporterv2/exporter_test.go index 608d968d92f..5bcb140e60f 100644 --- a/exporter/s3exporterv2/exporter_test.go +++ b/exporter/s3exporterv2/exporter_test.go @@ -2,11 +2,12 @@ package s3exporterv2 import ( "context" - "github.com/aws/aws-sdk-go-v2/aws" "log" "os" "testing" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/thomaspoignant/go-feature-flag/exporter" "github.com/stretchr/testify/assert" @@ -41,7 +42,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, expectedFile: "./testdata/all_default.json", @@ -56,7 +57,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, expectedFile: "./testdata/all_default.json", @@ -71,7 +72,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, expectedFile: "./testdata/all_default.csv", @@ -87,7 +88,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, expectedFile: "./testdata/custom_csv_format.csv", @@ -103,7 +104,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, expectedFile: "./testdata/all_default.json", @@ -118,7 +119,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, expectedFile: "./testdata/all_default.json", @@ -132,7 +133,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, wantErr: true, @@ -146,7 +147,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, wantErr: true, @@ -160,7 +161,7 @@ func TestS3_Export(t *testing.T) { events: []exporter.FeatureEvent{ { Kind: "feature", ContextKind: "anonymousUser", UserKey: "ABCD", CreationDate: 1617970547, Key: "random-key", - Variation: "Default", Value: "YO", Default: false, + Variation: "Default", Value: "YO", Default: false, Source: "SERVER", }, }, wantErr: true, diff --git a/exporter/s3exporterv2/testdata/all_default.csv b/exporter/s3exporterv2/testdata/all_default.csv index db122b68d71..60f91161919 100644 --- a/exporter/s3exporterv2/testdata/all_default.csv +++ b/exporter/s3exporterv2/testdata/all_default.csv @@ -1 +1 @@ -feature;anonymousUser;ABCD;1617970547;random-key;Default;YO;false +feature;anonymousUser;ABCD;1617970547;random-key;Default;YO;false;SERVER diff --git a/exporter/s3exporterv2/testdata/all_default.json b/exporter/s3exporterv2/testdata/all_default.json index 9e702153e2e..851a24887d6 100644 --- a/exporter/s3exporterv2/testdata/all_default.json +++ b/exporter/s3exporterv2/testdata/all_default.json @@ -1 +1 @@ -{"kind":"feature","contextKind":"anonymousUser","userKey":"ABCD","creationDate":1617970547,"key":"random-key","variation":"Default","value":"YO","default":false,"version":""} +{"kind":"feature","contextKind":"anonymousUser","userKey":"ABCD","creationDate":1617970547,"key":"random-key","variation":"Default","value":"YO","default":false,"version":"","source":"SERVER"} From 6335cdd97b5f41b1c60b0a54de7fb62a16b87fc2 Mon Sep 17 00:00:00 2001 From: drei Date: Tue, 26 Sep 2023 12:42:22 -0300 Subject: [PATCH 08/11] Update Swagger with the new Source field on the FeatureEvent --- cmd/relayproxy/docs/swagger.json | 5 +++++ cmd/relayproxy/docs/swagger.yaml | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/cmd/relayproxy/docs/swagger.json b/cmd/relayproxy/docs/swagger.json index a4cabb70a05..1544d4aef9d 100644 --- a/cmd/relayproxy/docs/swagger.json +++ b/cmd/relayproxy/docs/swagger.json @@ -290,6 +290,11 @@ "type": "string", "example": "feature" }, + "source": { + "description": "Source indicates where the event was generated.\nThis is set to SERVER when the event was evaluated in the relay-proxy and PROVIDER_CACHE when it is evaluated from the cache.", + "type": "string", + "example": "SERVER" + }, "userKey": { "description": "UserKey The key of the user object used in a feature flag evaluation. Details for the user object used in a feature\nflag evaluation as reported by the \"feature\" event are transmitted periodically with a separate index event.", "type": "string", diff --git a/cmd/relayproxy/docs/swagger.yaml b/cmd/relayproxy/docs/swagger.yaml index 16781352116..af871078a5c 100644 --- a/cmd/relayproxy/docs/swagger.yaml +++ b/cmd/relayproxy/docs/swagger.yaml @@ -29,6 +29,12 @@ definitions: A feature event will only be generated if the trackEvents attribute of the flag is set to true. example: feature type: string + source: + description: |- + Source indicates where the event was generated. + This is set to SERVER when the event was evaluated in the relay-proxy and PROVIDER_CACHE when it is evaluated from the cache. + example: SERVER + type: string userKey: description: |- UserKey The key of the user object used in a feature flag evaluation. Details for the user object used in a feature From 976659e3f79e83e91c1bfc309ede17bb4de93813 Mon Sep 17 00:00:00 2001 From: drei Date: Tue, 26 Sep 2023 22:04:26 -0300 Subject: [PATCH 09/11] Add 'source' field documentation to Swagger --- cmd/relayproxy/docs/docs.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd/relayproxy/docs/docs.go b/cmd/relayproxy/docs/docs.go index 409ec08c9f2..89d917fe0a8 100644 --- a/cmd/relayproxy/docs/docs.go +++ b/cmd/relayproxy/docs/docs.go @@ -298,6 +298,11 @@ const docTemplate = `{ "type": "string", "example": "feature" }, + "source": { + "description": "Source indicates where the event was generated.\nThis is set to SERVER when the event was evaluated in the relay-proxy and PROVIDER_CACHE when it is evaluated from the cache.", + "type": "string", + "example": "SERVER" + }, "userKey": { "description": "UserKey The key of the user object used in a feature flag evaluation. Details for the user object used in a feature\nflag evaluation as reported by the \"feature\" event are transmitted periodically with a separate index event.", "type": "string", From e682a84d5bebd86f1567a829fdcebf68da7b5df5 Mon Sep 17 00:00:00 2001 From: drei Date: Wed, 27 Sep 2023 17:13:30 -0300 Subject: [PATCH 10/11] Update cmd/relayproxy/controller/collect_eval_data.go Co-authored-by: Thomas Poignant --- cmd/relayproxy/controller/collect_eval_data.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/relayproxy/controller/collect_eval_data.go b/cmd/relayproxy/controller/collect_eval_data.go index 46bb29aa1eb..fdc5a1e2b40 100644 --- a/cmd/relayproxy/controller/collect_eval_data.go +++ b/cmd/relayproxy/controller/collect_eval_data.go @@ -47,7 +47,9 @@ func (h *collectEvalData) Handler(c echo.Context) error { } for _, event := range reqBody.Events { - event.Source = "PROVIDER_CACHE" + if event.Source == "" { + event.Source = "PROVIDER_CACHE" + } h.goFF.CollectEventData(event) } From c86b3c20947a9dabf83d5f2d358f0094b2f8d206 Mon Sep 17 00:00:00 2001 From: drei Date: Wed, 27 Sep 2023 18:12:35 -0300 Subject: [PATCH 11/11] include test for when a custom source field is provided --- .../controller/collect_eval_data_test.go | 28 +++++++++++++------ .../collected_data_with_source_field.json | 1 + .../request_with_source_field.json | 16 +++++++++++ 3 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 cmd/relayproxy/testdata/controller/collect_eval_data/collected_data_with_source_field.json create mode 100644 cmd/relayproxy/testdata/controller/collect_eval_data/request_with_source_field.json diff --git a/cmd/relayproxy/controller/collect_eval_data_test.go b/cmd/relayproxy/controller/collect_eval_data_test.go index 48ae0188329..4fff7c1af0f 100644 --- a/cmd/relayproxy/controller/collect_eval_data_test.go +++ b/cmd/relayproxy/controller/collect_eval_data_test.go @@ -2,14 +2,6 @@ package controller_test import ( "context" - "github.com/labstack/echo-contrib/prometheus" - "github.com/labstack/echo/v4" - "github.com/stretchr/testify/assert" - ffclient "github.com/thomaspoignant/go-feature-flag" - "github.com/thomaspoignant/go-feature-flag/cmd/relayproxy/controller" - "github.com/thomaspoignant/go-feature-flag/cmd/relayproxy/metric" - "github.com/thomaspoignant/go-feature-flag/exporter/fileexporter" - "github.com/thomaspoignant/go-feature-flag/retriever/fileretriever" "io" "log" "net/http" @@ -19,6 +11,15 @@ import ( "strings" "testing" "time" + + "github.com/labstack/echo-contrib/prometheus" + "github.com/labstack/echo/v4" + "github.com/stretchr/testify/assert" + ffclient "github.com/thomaspoignant/go-feature-flag" + "github.com/thomaspoignant/go-feature-flag/cmd/relayproxy/controller" + "github.com/thomaspoignant/go-feature-flag/cmd/relayproxy/metric" + "github.com/thomaspoignant/go-feature-flag/exporter/fileexporter" + "github.com/thomaspoignant/go-feature-flag/retriever/fileretriever" ) func Test_collect_eval_data_Handler(t *testing.T) { @@ -49,6 +50,17 @@ func Test_collect_eval_data_Handler(t *testing.T) { collectedDataFile: "../testdata/controller/collect_eval_data/valid_collected_data.json", }, }, + { + name: "valid with source field", + args: args{ + bodyFile: "../testdata/controller/collect_eval_data/request_with_source_field.json", + }, + want: want{ + httpCode: http.StatusOK, + bodyFile: "../testdata/controller/collect_eval_data/valid_response.json", + collectedDataFile: "../testdata/controller/collect_eval_data/collected_data_with_source_field.json", + }, + }, { name: "invalid json", args: args{ diff --git a/cmd/relayproxy/testdata/controller/collect_eval_data/collected_data_with_source_field.json b/cmd/relayproxy/testdata/controller/collect_eval_data/collected_data_with_source_field.json new file mode 100644 index 00000000000..6bc4280cd9b --- /dev/null +++ b/cmd/relayproxy/testdata/controller/collect_eval_data/collected_data_with_source_field.json @@ -0,0 +1 @@ +{"kind":"feature","contextKind":"user","userKey":"94a25909-20d8-40cc-8500-fee99b569345","creationDate":1680246000011,"key":"my-feature-flag","variation":"admin-variation","value":"string","default":false,"version":"v1.0.0","source":"EDGE"} diff --git a/cmd/relayproxy/testdata/controller/collect_eval_data/request_with_source_field.json b/cmd/relayproxy/testdata/controller/collect_eval_data/request_with_source_field.json new file mode 100644 index 00000000000..ad1a0ee66d5 --- /dev/null +++ b/cmd/relayproxy/testdata/controller/collect_eval_data/request_with_source_field.json @@ -0,0 +1,16 @@ +{ + "events": [ + { + "contextKind": "user", + "creationDate": 1680246000011, + "default": false, + "key": "my-feature-flag", + "kind": "feature", + "userKey": "94a25909-20d8-40cc-8500-fee99b569345", + "value": "string", + "variation": "admin-variation", + "version": "v1.0.0", + "source": "EDGE" + } + ] +} \ No newline at end of file