From 4b328db9575f46deb1da2206b84651b5d6ae107a Mon Sep 17 00:00:00 2001 From: "ci.datadog-api-spec" Date: Tue, 9 Jun 2026 01:25:14 +0000 Subject: [PATCH] Regenerate client from commit 302b39c of spec repo --- .generator/schemas/v2/openapi.yaml | 40 +++-- api/datadogV2/model_condition.go | 166 ++++++++++++------ api/datadogV2/model_condition_request.go | 152 ++++++++++------ ...eAllocationsForFeatureFlagInEnvironment.go | 5 +- ...eAllocationsForFeatureFlagInEnvironment.go | 5 +- .../features/v2/feature_flags.feature | 20 +-- 6 files changed, 255 insertions(+), 133 deletions(-) diff --git a/.generator/schemas/v2/openapi.yaml b/.generator/schemas/v2/openapi.yaml index 2d470c8f2f0..c5b00f59f4f 100644 --- a/.generator/schemas/v2/openapi.yaml +++ b/.generator/schemas/v2/openapi.yaml @@ -19568,10 +19568,14 @@ components: - CONTAINER - CALLOUTVALUE Condition: - description: Targeting condition details. + description: |- + Targeting condition details. A condition is either an inline + predicate with `operator`, `attribute`, and `value`, or a reference to a + saved filter with `saved_filter_id`. The inline fields are omitted for saved-filter + references. properties: attribute: - description: The user or request attribute to evaluate. + description: The user or request attribute to evaluate. Omitted for saved-filter references. example: "country" type: string created_at: @@ -19586,13 +19590,19 @@ components: type: string operator: $ref: "#/components/schemas/ConditionOperator" + saved_filter_id: + description: The ID of the saved filter referenced by this condition, or null for inline conditions. + example: "550e8400-e29b-41d4-a716-446655440090" + format: uuid + nullable: true + type: string updated_at: description: The timestamp when the condition was last updated. example: "2024-01-01T12:00:00Z" format: date-time type: string value: - description: Values used by the selected operator. + description: Values used by the selected operator. Omitted for saved-filter references. example: ["US", "CA"] items: description: Target value for the selected operator. @@ -19600,9 +19610,6 @@ components: type: array required: - id - - operator - - attribute - - value - created_at - updated_at type: object @@ -19633,25 +19640,32 @@ components: - IS_NULL - EQUALS ConditionRequest: - description: Condition request payload for targeting rules. + description: |- + Condition request payload for targeting rules. A condition is either an inline + predicate with `operator`, `attribute`, and `value`, or a reference to a + saved filter with `saved_filter_id`. The two shapes are mutually exclusive. properties: attribute: - description: The user or request attribute to evaluate. + description: The user or request attribute to evaluate. Required for inline conditions; omit when `saved_filter_id` is set. example: "user_tier" type: string operator: $ref: "#/components/schemas/ConditionOperator" + saved_filter_id: + description: |- + The ID of a saved filter to reference as this condition. Mutually exclusive + with `operator`, `attribute`, and `value`. When set, the saved filter's + targeting rules are evaluated in place of an inline predicate. + example: "550e8400-e29b-41d4-a716-446655440090" + format: uuid + type: string value: - description: Values used by the selected operator. + description: Values used by the selected operator. Required for inline conditions; omit when `saved_filter_id` is set. example: ["premium", "enterprise"] items: description: Target value for the selected operator. type: string type: array - required: - - operator - - attribute - - value type: object ConfigCatCredentials: description: The definition of the `ConfigCatCredentials` object. diff --git a/api/datadogV2/model_condition.go b/api/datadogV2/model_condition.go index 08c07be0bfe..63376418e66 100644 --- a/api/datadogV2/model_condition.go +++ b/api/datadogV2/model_condition.go @@ -13,20 +13,25 @@ import ( "github.com/DataDog/datadog-api-client-go/v2/api/datadog" ) -// Condition Targeting condition details. +// Condition Targeting condition details. A condition is either an inline +// predicate with `operator`, `attribute`, and `value`, or a reference to a +// saved filter with `saved_filter_id`. The inline fields are omitted for saved-filter +// references. type Condition struct { - // The user or request attribute to evaluate. - Attribute string `json:"attribute"` + // The user or request attribute to evaluate. Omitted for saved-filter references. + Attribute *string `json:"attribute,omitempty"` // The timestamp when the condition was created. CreatedAt time.Time `json:"created_at"` // The unique identifier of the condition. Id uuid.UUID `json:"id"` // The operator used in a targeting condition. - Operator ConditionOperator `json:"operator"` + Operator *ConditionOperator `json:"operator,omitempty"` + // The ID of the saved filter referenced by this condition, or null for inline conditions. + SavedFilterId datadog.NullableUUID `json:"saved_filter_id,omitempty"` // The timestamp when the condition was last updated. UpdatedAt time.Time `json:"updated_at"` - // Values used by the selected operator. - Value []string `json:"value"` + // Values used by the selected operator. Omitted for saved-filter references. + Value []string `json:"value,omitempty"` // UnparsedObject contains the raw value of the object if there was an error when deserializing into the struct UnparsedObject map[string]interface{} `json:"-"` AdditionalProperties map[string]interface{} `json:"-"` @@ -36,14 +41,11 @@ type Condition struct { // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed. -func NewCondition(attribute string, createdAt time.Time, id uuid.UUID, operator ConditionOperator, updatedAt time.Time, value []string) *Condition { +func NewCondition(createdAt time.Time, id uuid.UUID, updatedAt time.Time) *Condition { this := Condition{} - this.Attribute = attribute this.CreatedAt = createdAt this.Id = id - this.Operator = operator this.UpdatedAt = updatedAt - this.Value = value return &this } @@ -55,27 +57,32 @@ func NewConditionWithDefaults() *Condition { return &this } -// GetAttribute returns the Attribute field value. +// GetAttribute returns the Attribute field value if set, zero value otherwise. func (o *Condition) GetAttribute() string { - if o == nil { + if o == nil || o.Attribute == nil { var ret string return ret } - return o.Attribute + return *o.Attribute } -// GetAttributeOk returns a tuple with the Attribute field value +// GetAttributeOk returns a tuple with the Attribute field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *Condition) GetAttributeOk() (*string, bool) { - if o == nil { + if o == nil || o.Attribute == nil { return nil, false } - return &o.Attribute, true + return o.Attribute, true } -// SetAttribute sets field value. +// HasAttribute returns a boolean if a field has been set. +func (o *Condition) HasAttribute() bool { + return o != nil && o.Attribute != nil +} + +// SetAttribute gets a reference to the given string and assigns it to the Attribute field. func (o *Condition) SetAttribute(v string) { - o.Attribute = v + o.Attribute = &v } // GetCreatedAt returns the CreatedAt field value. @@ -124,27 +131,71 @@ func (o *Condition) SetId(v uuid.UUID) { o.Id = v } -// GetOperator returns the Operator field value. +// GetOperator returns the Operator field value if set, zero value otherwise. func (o *Condition) GetOperator() ConditionOperator { - if o == nil { + if o == nil || o.Operator == nil { var ret ConditionOperator return ret } - return o.Operator + return *o.Operator } -// GetOperatorOk returns a tuple with the Operator field value +// GetOperatorOk returns a tuple with the Operator field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *Condition) GetOperatorOk() (*ConditionOperator, bool) { - if o == nil { + if o == nil || o.Operator == nil { return nil, false } - return &o.Operator, true + return o.Operator, true +} + +// HasOperator returns a boolean if a field has been set. +func (o *Condition) HasOperator() bool { + return o != nil && o.Operator != nil } -// SetOperator sets field value. +// SetOperator gets a reference to the given ConditionOperator and assigns it to the Operator field. func (o *Condition) SetOperator(v ConditionOperator) { - o.Operator = v + o.Operator = &v +} + +// GetSavedFilterId returns the SavedFilterId field value if set, zero value otherwise (both if not set or set to explicit null). +func (o *Condition) GetSavedFilterId() uuid.UUID { + if o == nil || o.SavedFilterId.Get() == nil { + var ret uuid.UUID + return ret + } + return *o.SavedFilterId.Get() +} + +// GetSavedFilterIdOk returns a tuple with the SavedFilterId field value if set, nil otherwise +// and a boolean to check if the value has been set. +// NOTE: If the value is an explicit nil, `nil, true` will be returned. +func (o *Condition) GetSavedFilterIdOk() (*uuid.UUID, bool) { + if o == nil { + return nil, false + } + return o.SavedFilterId.Get(), o.SavedFilterId.IsSet() +} + +// HasSavedFilterId returns a boolean if a field has been set. +func (o *Condition) HasSavedFilterId() bool { + return o != nil && o.SavedFilterId.IsSet() +} + +// SetSavedFilterId gets a reference to the given datadog.NullableUUID and assigns it to the SavedFilterId field. +func (o *Condition) SetSavedFilterId(v uuid.UUID) { + o.SavedFilterId.Set(&v) +} + +// SetSavedFilterIdNil sets the value for SavedFilterId to be an explicit nil. +func (o *Condition) SetSavedFilterIdNil() { + o.SavedFilterId.Set(nil) +} + +// UnsetSavedFilterId ensures that no value is present for SavedFilterId, not even an explicit nil. +func (o *Condition) UnsetSavedFilterId() { + o.SavedFilterId.Unset() } // GetUpdatedAt returns the UpdatedAt field value. @@ -170,25 +221,30 @@ func (o *Condition) SetUpdatedAt(v time.Time) { o.UpdatedAt = v } -// GetValue returns the Value field value. +// GetValue returns the Value field value if set, zero value otherwise. func (o *Condition) GetValue() []string { - if o == nil { + if o == nil || o.Value == nil { var ret []string return ret } return o.Value } -// GetValueOk returns a tuple with the Value field value +// GetValueOk returns a tuple with the Value field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *Condition) GetValueOk() (*[]string, bool) { - if o == nil { + if o == nil || o.Value == nil { return nil, false } return &o.Value, true } -// SetValue sets field value. +// HasValue returns a boolean if a field has been set. +func (o *Condition) HasValue() bool { + return o != nil && o.Value != nil +} + +// SetValue gets a reference to the given []string and assigns it to the Value field. func (o *Condition) SetValue(v []string) { o.Value = v } @@ -199,20 +255,29 @@ func (o Condition) MarshalJSON() ([]byte, error) { if o.UnparsedObject != nil { return datadog.Marshal(o.UnparsedObject) } - toSerialize["attribute"] = o.Attribute + if o.Attribute != nil { + toSerialize["attribute"] = o.Attribute + } if o.CreatedAt.Nanosecond() == 0 { toSerialize["created_at"] = o.CreatedAt.Format("2006-01-02T15:04:05Z07:00") } else { toSerialize["created_at"] = o.CreatedAt.Format("2006-01-02T15:04:05.000Z07:00") } toSerialize["id"] = o.Id - toSerialize["operator"] = o.Operator + if o.Operator != nil { + toSerialize["operator"] = o.Operator + } + if o.SavedFilterId.IsSet() { + toSerialize["saved_filter_id"] = o.SavedFilterId.Get() + } if o.UpdatedAt.Nanosecond() == 0 { toSerialize["updated_at"] = o.UpdatedAt.Format("2006-01-02T15:04:05Z07:00") } else { toSerialize["updated_at"] = o.UpdatedAt.Format("2006-01-02T15:04:05.000Z07:00") } - toSerialize["value"] = o.Value + if o.Value != nil { + toSerialize["value"] = o.Value + } for key, value := range o.AdditionalProperties { toSerialize[key] = value @@ -223,52 +288,45 @@ func (o Condition) MarshalJSON() ([]byte, error) { // UnmarshalJSON deserializes the given payload. func (o *Condition) UnmarshalJSON(bytes []byte) (err error) { all := struct { - Attribute *string `json:"attribute"` - CreatedAt *time.Time `json:"created_at"` - Id *uuid.UUID `json:"id"` - Operator *ConditionOperator `json:"operator"` - UpdatedAt *time.Time `json:"updated_at"` - Value *[]string `json:"value"` + Attribute *string `json:"attribute,omitempty"` + CreatedAt *time.Time `json:"created_at"` + Id *uuid.UUID `json:"id"` + Operator *ConditionOperator `json:"operator,omitempty"` + SavedFilterId datadog.NullableUUID `json:"saved_filter_id,omitempty"` + UpdatedAt *time.Time `json:"updated_at"` + Value []string `json:"value,omitempty"` }{} if err = datadog.Unmarshal(bytes, &all); err != nil { return datadog.Unmarshal(bytes, &o.UnparsedObject) } - if all.Attribute == nil { - return fmt.Errorf("required field attribute missing") - } if all.CreatedAt == nil { return fmt.Errorf("required field created_at missing") } if all.Id == nil { return fmt.Errorf("required field id missing") } - if all.Operator == nil { - return fmt.Errorf("required field operator missing") - } if all.UpdatedAt == nil { return fmt.Errorf("required field updated_at missing") } - if all.Value == nil { - return fmt.Errorf("required field value missing") - } additionalProperties := make(map[string]interface{}) if err = datadog.UnmarshalUseNumber(bytes, &additionalProperties); err == nil { - datadog.DeleteKeys(additionalProperties, &[]string{"attribute", "created_at", "id", "operator", "updated_at", "value"}) + datadog.DeleteKeys(additionalProperties, &[]string{"attribute", "created_at", "id", "operator", "saved_filter_id", "updated_at", "value"}) } else { return err } hasInvalidField := false - o.Attribute = *all.Attribute + o.Attribute = all.Attribute o.CreatedAt = *all.CreatedAt o.Id = *all.Id - if !all.Operator.IsValid() { + if all.Operator != nil && !all.Operator.IsValid() { hasInvalidField = true } else { - o.Operator = *all.Operator + o.Operator = all.Operator } + o.SavedFilterId = all.SavedFilterId o.UpdatedAt = *all.UpdatedAt - o.Value = *all.Value + o.Value = all.Value if len(additionalProperties) > 0 { o.AdditionalProperties = additionalProperties diff --git a/api/datadogV2/model_condition_request.go b/api/datadogV2/model_condition_request.go index 3f21f0400ee..52fa905e437 100644 --- a/api/datadogV2/model_condition_request.go +++ b/api/datadogV2/model_condition_request.go @@ -5,19 +5,25 @@ package datadogV2 import ( - "fmt" + "github.com/google/uuid" "github.com/DataDog/datadog-api-client-go/v2/api/datadog" ) -// ConditionRequest Condition request payload for targeting rules. +// ConditionRequest Condition request payload for targeting rules. A condition is either an inline +// predicate with `operator`, `attribute`, and `value`, or a reference to a +// saved filter with `saved_filter_id`. The two shapes are mutually exclusive. type ConditionRequest struct { - // The user or request attribute to evaluate. - Attribute string `json:"attribute"` + // The user or request attribute to evaluate. Required for inline conditions; omit when `saved_filter_id` is set. + Attribute *string `json:"attribute,omitempty"` // The operator used in a targeting condition. - Operator ConditionOperator `json:"operator"` - // Values used by the selected operator. - Value []string `json:"value"` + Operator *ConditionOperator `json:"operator,omitempty"` + // The ID of a saved filter to reference as this condition. Mutually exclusive + // with `operator`, `attribute`, and `value`. When set, the saved filter's + // targeting rules are evaluated in place of an inline predicate. + SavedFilterId *uuid.UUID `json:"saved_filter_id,omitempty"` + // Values used by the selected operator. Required for inline conditions; omit when `saved_filter_id` is set. + Value []string `json:"value,omitempty"` // UnparsedObject contains the raw value of the object if there was an error when deserializing into the struct UnparsedObject map[string]interface{} `json:"-"` AdditionalProperties map[string]interface{} `json:"-"` @@ -27,11 +33,8 @@ type ConditionRequest struct { // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed. -func NewConditionRequest(attribute string, operator ConditionOperator, value []string) *ConditionRequest { +func NewConditionRequest() *ConditionRequest { this := ConditionRequest{} - this.Attribute = attribute - this.Operator = operator - this.Value = value return &this } @@ -43,71 +46,114 @@ func NewConditionRequestWithDefaults() *ConditionRequest { return &this } -// GetAttribute returns the Attribute field value. +// GetAttribute returns the Attribute field value if set, zero value otherwise. func (o *ConditionRequest) GetAttribute() string { - if o == nil { + if o == nil || o.Attribute == nil { var ret string return ret } - return o.Attribute + return *o.Attribute } -// GetAttributeOk returns a tuple with the Attribute field value +// GetAttributeOk returns a tuple with the Attribute field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *ConditionRequest) GetAttributeOk() (*string, bool) { - if o == nil { + if o == nil || o.Attribute == nil { return nil, false } - return &o.Attribute, true + return o.Attribute, true } -// SetAttribute sets field value. +// HasAttribute returns a boolean if a field has been set. +func (o *ConditionRequest) HasAttribute() bool { + return o != nil && o.Attribute != nil +} + +// SetAttribute gets a reference to the given string and assigns it to the Attribute field. func (o *ConditionRequest) SetAttribute(v string) { - o.Attribute = v + o.Attribute = &v } -// GetOperator returns the Operator field value. +// GetOperator returns the Operator field value if set, zero value otherwise. func (o *ConditionRequest) GetOperator() ConditionOperator { - if o == nil { + if o == nil || o.Operator == nil { var ret ConditionOperator return ret } - return o.Operator + return *o.Operator } -// GetOperatorOk returns a tuple with the Operator field value +// GetOperatorOk returns a tuple with the Operator field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *ConditionRequest) GetOperatorOk() (*ConditionOperator, bool) { - if o == nil { + if o == nil || o.Operator == nil { return nil, false } - return &o.Operator, true + return o.Operator, true +} + +// HasOperator returns a boolean if a field has been set. +func (o *ConditionRequest) HasOperator() bool { + return o != nil && o.Operator != nil } -// SetOperator sets field value. +// SetOperator gets a reference to the given ConditionOperator and assigns it to the Operator field. func (o *ConditionRequest) SetOperator(v ConditionOperator) { - o.Operator = v + o.Operator = &v +} + +// GetSavedFilterId returns the SavedFilterId field value if set, zero value otherwise. +func (o *ConditionRequest) GetSavedFilterId() uuid.UUID { + if o == nil || o.SavedFilterId == nil { + var ret uuid.UUID + return ret + } + return *o.SavedFilterId +} + +// GetSavedFilterIdOk returns a tuple with the SavedFilterId field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ConditionRequest) GetSavedFilterIdOk() (*uuid.UUID, bool) { + if o == nil || o.SavedFilterId == nil { + return nil, false + } + return o.SavedFilterId, true } -// GetValue returns the Value field value. +// HasSavedFilterId returns a boolean if a field has been set. +func (o *ConditionRequest) HasSavedFilterId() bool { + return o != nil && o.SavedFilterId != nil +} + +// SetSavedFilterId gets a reference to the given uuid.UUID and assigns it to the SavedFilterId field. +func (o *ConditionRequest) SetSavedFilterId(v uuid.UUID) { + o.SavedFilterId = &v +} + +// GetValue returns the Value field value if set, zero value otherwise. func (o *ConditionRequest) GetValue() []string { - if o == nil { + if o == nil || o.Value == nil { var ret []string return ret } return o.Value } -// GetValueOk returns a tuple with the Value field value +// GetValueOk returns a tuple with the Value field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *ConditionRequest) GetValueOk() (*[]string, bool) { - if o == nil { + if o == nil || o.Value == nil { return nil, false } return &o.Value, true } -// SetValue sets field value. +// HasValue returns a boolean if a field has been set. +func (o *ConditionRequest) HasValue() bool { + return o != nil && o.Value != nil +} + +// SetValue gets a reference to the given []string and assigns it to the Value field. func (o *ConditionRequest) SetValue(v []string) { o.Value = v } @@ -118,9 +164,18 @@ func (o ConditionRequest) MarshalJSON() ([]byte, error) { if o.UnparsedObject != nil { return datadog.Marshal(o.UnparsedObject) } - toSerialize["attribute"] = o.Attribute - toSerialize["operator"] = o.Operator - toSerialize["value"] = o.Value + if o.Attribute != nil { + toSerialize["attribute"] = o.Attribute + } + if o.Operator != nil { + toSerialize["operator"] = o.Operator + } + if o.SavedFilterId != nil { + toSerialize["saved_filter_id"] = o.SavedFilterId + } + if o.Value != nil { + toSerialize["value"] = o.Value + } for key, value := range o.AdditionalProperties { toSerialize[key] = value @@ -131,37 +186,30 @@ func (o ConditionRequest) MarshalJSON() ([]byte, error) { // UnmarshalJSON deserializes the given payload. func (o *ConditionRequest) UnmarshalJSON(bytes []byte) (err error) { all := struct { - Attribute *string `json:"attribute"` - Operator *ConditionOperator `json:"operator"` - Value *[]string `json:"value"` + Attribute *string `json:"attribute,omitempty"` + Operator *ConditionOperator `json:"operator,omitempty"` + SavedFilterId *uuid.UUID `json:"saved_filter_id,omitempty"` + Value []string `json:"value,omitempty"` }{} if err = datadog.Unmarshal(bytes, &all); err != nil { return datadog.Unmarshal(bytes, &o.UnparsedObject) } - if all.Attribute == nil { - return fmt.Errorf("required field attribute missing") - } - if all.Operator == nil { - return fmt.Errorf("required field operator missing") - } - if all.Value == nil { - return fmt.Errorf("required field value missing") - } additionalProperties := make(map[string]interface{}) if err = datadog.UnmarshalUseNumber(bytes, &additionalProperties); err == nil { - datadog.DeleteKeys(additionalProperties, &[]string{"attribute", "operator", "value"}) + datadog.DeleteKeys(additionalProperties, &[]string{"attribute", "operator", "saved_filter_id", "value"}) } else { return err } hasInvalidField := false - o.Attribute = *all.Attribute - if !all.Operator.IsValid() { + o.Attribute = all.Attribute + if all.Operator != nil && !all.Operator.IsValid() { hasInvalidField = true } else { - o.Operator = *all.Operator + o.Operator = all.Operator } - o.Value = *all.Value + o.SavedFilterId = all.SavedFilterId + o.Value = all.Value if len(additionalProperties) > 0 { o.AdditionalProperties = additionalProperties diff --git a/examples/v2/feature-flags/CreateAllocationsForFeatureFlagInEnvironment.go b/examples/v2/feature-flags/CreateAllocationsForFeatureFlagInEnvironment.go index 41371820135..9d0739f53f6 100644 --- a/examples/v2/feature-flags/CreateAllocationsForFeatureFlagInEnvironment.go +++ b/examples/v2/feature-flags/CreateAllocationsForFeatureFlagInEnvironment.go @@ -52,8 +52,9 @@ func main() { { Conditions: []datadogV2.ConditionRequest{ { - Attribute: "user_tier", - Operator: datadogV2.CONDITIONOPERATOR_ONE_OF, + Attribute: datadog.PtrString("user_tier"), + Operator: datadogV2.CONDITIONOPERATOR_ONE_OF.Ptr(), + SavedFilterId: datadog.PtrUUID(uuid.MustParse("550e8400-e29b-41d4-a716-446655440090")), Value: []string{ "premium", "enterprise", diff --git a/examples/v2/feature-flags/UpdateAllocationsForFeatureFlagInEnvironment.go b/examples/v2/feature-flags/UpdateAllocationsForFeatureFlagInEnvironment.go index 3a5573a8250..743f7b3e63a 100644 --- a/examples/v2/feature-flags/UpdateAllocationsForFeatureFlagInEnvironment.go +++ b/examples/v2/feature-flags/UpdateAllocationsForFeatureFlagInEnvironment.go @@ -53,8 +53,9 @@ func main() { { Conditions: []datadogV2.ConditionRequest{ { - Attribute: "user_tier", - Operator: datadogV2.CONDITIONOPERATOR_ONE_OF, + Attribute: datadog.PtrString("user_tier"), + Operator: datadogV2.CONDITIONOPERATOR_ONE_OF.Ptr(), + SavedFilterId: datadog.PtrUUID(uuid.MustParse("550e8400-e29b-41d4-a716-446655440090")), Value: []string{ "premium", "enterprise", diff --git a/tests/scenarios/features/v2/feature_flags.feature b/tests/scenarios/features/v2/feature_flags.feature index df31d246a42..d8238606bff 100644 --- a/tests/scenarios/features/v2/feature_flags.feature +++ b/tests/scenarios/features/v2/feature_flags.feature @@ -90,7 +90,7 @@ Feature: Feature Flags Given new "CreateAllocationsForFeatureFlagInEnvironment" request And request contains "feature_flag_id" parameter from "REPLACE.ME" And request contains "environment_id" parameter from "REPLACE.ME" - And body with value {"data": {"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}} + And body with value {"data": {"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "saved_filter_id": "550e8400-e29b-41d4-a716-446655440090", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}} When the request is sent Then the response status is 202 Accepted - Approval required for this change @@ -99,7 +99,7 @@ Feature: Feature Flags Given new "CreateAllocationsForFeatureFlagInEnvironment" request And request contains "feature_flag_id" parameter from "REPLACE.ME" And request contains "environment_id" parameter from "REPLACE.ME" - And body with value {"data": {"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}} + And body with value {"data": {"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "saved_filter_id": "550e8400-e29b-41d4-a716-446655440090", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}} When the request is sent Then the response status is 400 Bad Request @@ -108,7 +108,7 @@ Feature: Feature Flags Given new "CreateAllocationsForFeatureFlagInEnvironment" request And request contains "feature_flag_id" parameter from "REPLACE.ME" And request contains "environment_id" parameter from "REPLACE.ME" - And body with value {"data": {"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}} + And body with value {"data": {"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "saved_filter_id": "550e8400-e29b-41d4-a716-446655440090", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}} When the request is sent Then the response status is 409 Conflict @@ -117,7 +117,7 @@ Feature: Feature Flags Given new "CreateAllocationsForFeatureFlagInEnvironment" request And request contains "feature_flag_id" parameter from "REPLACE.ME" And request contains "environment_id" parameter from "REPLACE.ME" - And body with value {"data": {"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}} + And body with value {"data": {"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "saved_filter_id": "550e8400-e29b-41d4-a716-446655440090", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}} When the request is sent Then the response status is 201 Created @@ -126,7 +126,7 @@ Feature: Feature Flags Given new "CreateAllocationsForFeatureFlagInEnvironment" request And request contains "feature_flag_id" parameter from "REPLACE.ME" And request contains "environment_id" parameter from "REPLACE.ME" - And body with value {"data": {"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}} + And body with value {"data": {"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "saved_filter_id": "550e8400-e29b-41d4-a716-446655440090", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}} When the request is sent Then the response status is 404 Not Found @@ -449,7 +449,7 @@ Feature: Feature Flags Given new "UpdateAllocationsForFeatureFlagInEnvironment" request And request contains "feature_flag_id" parameter from "REPLACE.ME" And request contains "environment_id" parameter from "REPLACE.ME" - And body with value {"data": [{"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}]} + And body with value {"data": [{"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "saved_filter_id": "550e8400-e29b-41d4-a716-446655440090", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}]} When the request is sent Then the response status is 202 Accepted - Approval required for this change @@ -458,7 +458,7 @@ Feature: Feature Flags Given new "UpdateAllocationsForFeatureFlagInEnvironment" request And request contains "feature_flag_id" parameter from "REPLACE.ME" And request contains "environment_id" parameter from "REPLACE.ME" - And body with value {"data": [{"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}]} + And body with value {"data": [{"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "saved_filter_id": "550e8400-e29b-41d4-a716-446655440090", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}]} When the request is sent Then the response status is 400 Bad Request @@ -467,7 +467,7 @@ Feature: Feature Flags Given new "UpdateAllocationsForFeatureFlagInEnvironment" request And request contains "feature_flag_id" parameter from "REPLACE.ME" And request contains "environment_id" parameter from "REPLACE.ME" - And body with value {"data": [{"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}]} + And body with value {"data": [{"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "saved_filter_id": "550e8400-e29b-41d4-a716-446655440090", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}]} When the request is sent Then the response status is 409 Conflict @@ -476,7 +476,7 @@ Feature: Feature Flags Given new "UpdateAllocationsForFeatureFlagInEnvironment" request And request contains "feature_flag_id" parameter from "REPLACE.ME" And request contains "environment_id" parameter from "REPLACE.ME" - And body with value {"data": [{"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}]} + And body with value {"data": [{"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "saved_filter_id": "550e8400-e29b-41d4-a716-446655440090", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}]} When the request is sent Then the response status is 404 Not Found @@ -485,6 +485,6 @@ Feature: Feature Flags Given new "UpdateAllocationsForFeatureFlagInEnvironment" request And request contains "feature_flag_id" parameter from "REPLACE.ME" And request contains "environment_id" parameter from "REPLACE.ME" - And body with value {"data": [{"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}]} + And body with value {"data": [{"attributes": {"experiment_id": "550e8400-e29b-41d4-a716-446655440030", "exposure_schedule": {"absolute_start_time": "2025-06-13T12:00:00Z", "control_variant_id": "550e8400-e29b-41d4-a716-446655440012", "control_variant_key": "control", "id": "550e8400-e29b-41d4-a716-446655440010", "rollout_options": {"autostart": false, "selection_interval_ms": 3600000, "strategy": "UNIFORM_INTERVALS"}, "rollout_steps": [{"exposure_ratio": 0.5, "grouped_step_index": 1, "id": "550e8400-e29b-41d4-a716-446655440040", "interval_ms": 3600000, "is_pause_record": false}]}, "guardrail_metrics": [{"metric_id": "metric-error-rate", "trigger_action": "PAUSE"}], "id": "550e8400-e29b-41d4-a716-446655440020", "key": "prod-rollout", "name": "Production Rollout", "targeting_rules": [{"conditions": [{"attribute": "user_tier", "operator": "ONE_OF", "saved_filter_id": "550e8400-e29b-41d4-a716-446655440090", "value": ["premium", "enterprise"]}]}], "type": "FEATURE_GATE", "variant_weights": [{"value": 50, "variant_id": "550e8400-e29b-41d4-a716-446655440001", "variant_key": "control"}]}, "type": "allocations"}]} When the request is sent Then the response status is 200 OK