diff --git a/core/pkg/evaluator/json.go b/core/pkg/evaluator/json.go index 655eaf75c..1e18af4e4 100644 --- a/core/pkg/evaluator/json.go +++ b/core/pkg/evaluator/json.go @@ -327,6 +327,13 @@ func (je *Resolver) evaluateVariant(ctx context.Context, reqID string, flagKey s metadata[SelectorMetadataKey] = selector } + for key, value := range flag.Metadata { + // If value is not nil or empty, copy to metadata + if value != nil { + metadata[key] = value + } + } + if flag.State == Disabled { je.Logger.DebugWithID(reqID, fmt.Sprintf("requested flag is disabled: %s", flagKey)) return "", flag.Variants, model.ErrorReason, metadata, errors.New(model.FlagDisabledErrorCode) @@ -460,11 +467,28 @@ func configToFlags(log *logger.Logger, config string, newFlags *Flags) error { return fmt.Errorf("transposing evaluators: %w", err) } - err = json.Unmarshal([]byte(transposedConfig), &newFlags) + var configData ConfigWithMetadata + err = json.Unmarshal([]byte(transposedConfig), &configData) if err != nil { return fmt.Errorf("unmarshalling provided configurations: %w", err) } + // Assign the flags from the unmarshalled config to the newFlags struct + newFlags.Flags = configData.Flags + + // Assign metadata as a map to each flag's metadata + for key, flag := range newFlags.Flags { + if flag.Metadata == nil { + flag.Metadata = make(map[string]interface{}) + } + for metaKey, metaValue := range configData.Metadata { + if _, exists := flag.Metadata[metaKey]; !exists { + flag.Metadata[metaKey] = metaValue + } + } + newFlags.Flags[key] = flag + } + return validateDefaultVariants(newFlags) } diff --git a/core/pkg/evaluator/json_model.go b/core/pkg/evaluator/json_model.go index 00a7105ef..8b9c17114 100644 --- a/core/pkg/evaluator/json_model.go +++ b/core/pkg/evaluator/json_model.go @@ -10,6 +10,11 @@ type Evaluators struct { Evaluators map[string]json.RawMessage `json:"$evaluators"` } +type ConfigWithMetadata struct { + Flags map[string]model.Flag `json:"flags"` + Metadata map[string]interface{} `json:"metadata"` +} + type Flags struct { Flags map[string]model.Flag `json:"flags"` } diff --git a/core/pkg/evaluator/json_test.go b/core/pkg/evaluator/json_test.go index 8954a518e..b7f64ebf5 100644 --- a/core/pkg/evaluator/json_test.go +++ b/core/pkg/evaluator/json_test.go @@ -1184,6 +1184,222 @@ func TestState_Evaluator(t *testing.T) { expectedError: true, expectedResync: false, }, + "flag metadata": { + inputState: ` + { + "flags": { + "fibAlgo": { + "variants": { + "recursive": "recursive", + "memo": "memo", + "loop": "loop", + "binet": "binet" + }, + "metadata": { + "id": 1 + }, + "defaultVariant": "recursive", + "state": "ENABLED", + "targeting": { + "if": [ + { + "$ref": "emailWithFaas" + }, "binet", null + ] + } + } + }, + "$evaluators": { + "emailWithFaas": { + "in": ["@faas.com", { + "var": ["email"] + }] + } + } + } + `, + inputSyncType: sync.ALL, + expectedOutputState: ` + { + "flags": { + "fibAlgo": { + "variants": { + "recursive": "recursive", + "memo": "memo", + "loop": "loop", + "binet": "binet" + }, + "metadata": { + "id": 1 + }, + "defaultVariant": "recursive", + "state": "ENABLED", + "source":"", + "selector":"", + "targeting": { + "if": [ + { + "in": ["@faas.com", { + "var": ["email"] + }] + }, "binet", null + ] + } + } + }, + "flagSources":null + } + `, + }, + "flagSet and flag metadata": { + inputState: ` + { + "flags": { + "fibAlgo": { + "variants": { + "recursive": "recursive", + "memo": "memo", + "loop": "loop", + "binet": "binet" + }, + "metadata": { + "id": "sso/dev", + "version": "1.0.0" + }, + "defaultVariant": "recursive", + "state": "ENABLED", + "targeting": { + "if": [ + { + "$ref": "emailWithFaas" + }, "binet", null + ] + } + } + }, + "metadata": { + "flagSetId": "test", + "flagSetVersion": "1" + }, + "$evaluators": { + "emailWithFaas": { + "in": ["@faas.com", { + "var": ["email"] + }] + } + } + } + `, + inputSyncType: sync.ALL, + expectedOutputState: ` + { + "flags": { + "fibAlgo": { + "variants": { + "recursive": "recursive", + "memo": "memo", + "loop": "loop", + "binet": "binet" + }, + "metadata": { + "id": "sso/dev", + "version": "1.0.0", + "flagSetId": "test", + "flagSetVersion": "1" + }, + "defaultVariant": "recursive", + "state": "ENABLED", + "source":"", + "selector":"", + "targeting": { + "if": [ + { + "in": ["@faas.com", { + "var": ["email"] + }] + }, "binet", null + ] + } + } + }, + "flagSources":null + } + `, + }, + "flag metadata priority": { + inputState: ` + { + "flags": { + "fibAlgo": { + "variants": { + "recursive": "recursive", + "memo": "memo", + "loop": "loop", + "binet": "binet" + }, + "metadata": { + "id": "sso/dev", + "version": "1.0.0" + }, + "defaultVariant": "recursive", + "state": "ENABLED", + "targeting": { + "if": [ + { + "$ref": "emailWithFaas" + }, "binet", null + ] + } + } + }, + "metadata": { + "id": "test", + "flagSetVersion": "1" + }, + "$evaluators": { + "emailWithFaas": { + "in": ["@faas.com", { + "var": ["email"] + }] + } + } + } + `, + inputSyncType: sync.ALL, + expectedOutputState: ` + { + "flags": { + "fibAlgo": { + "variants": { + "recursive": "recursive", + "memo": "memo", + "loop": "loop", + "binet": "binet" + }, + "metadata": { + "id": "sso/dev", + "version": "1.0.0", + "flagSetVersion": "1" + }, + "defaultVariant": "recursive", + "state": "ENABLED", + "source":"", + "selector":"", + "targeting": { + "if": [ + { + "in": ["@faas.com", { + "var": ["email"] + }] + }, "binet", null + ] + } + } + }, + "flagSources":null + } + `, + }, } for name, tt := range tests { diff --git a/core/pkg/model/flag.go b/core/pkg/model/flag.go index 342b0488b..281ee9d02 100644 --- a/core/pkg/model/flag.go +++ b/core/pkg/model/flag.go @@ -3,12 +3,13 @@ package model import "encoding/json" type Flag struct { - State string `json:"state"` - DefaultVariant string `json:"defaultVariant"` - Variants map[string]any `json:"variants"` - Targeting json.RawMessage `json:"targeting,omitempty"` - Source string `json:"source"` - Selector string `json:"selector"` + State string `json:"state"` + DefaultVariant string `json:"defaultVariant"` + Variants map[string]any `json:"variants"` + Targeting json.RawMessage `json:"targeting,omitempty"` + Source string `json:"source"` + Selector string `json:"selector"` + Metadata map[string]interface{} `json:"metadata,omitempty"` } type Evaluators struct { diff --git a/core/pkg/store/flags.go b/core/pkg/store/flags.go index 626e2940f..8acfded21 100644 --- a/core/pkg/store/flags.go +++ b/core/pkg/store/flags.go @@ -21,7 +21,8 @@ type Flags struct { mx sync.RWMutex Flags map[string]model.Flag `json:"flags"` FlagSources []string - SourceMetadata map[string]SourceDetails + SourceMetadata map[string]SourceDetails `json:"sourceMetadata,omitempty"` + Metadata map[string]interface{} `json:"metadata,omitempty"` } type SourceDetails struct {