From 6a28a8b03b830d8d0c510f0e1fbf6e4f2debc5a1 Mon Sep 17 00:00:00 2001 From: Florian Gessner Date: Wed, 14 Oct 2020 21:09:14 +0200 Subject: [PATCH] #69: Fix incompatible change of equal condition operator --- ...nstana_custom_event_spec_threshold_rule.md | 5 +- ...-specficiation-entity-verification-rule.go | 4 +- ...stom-event-specficiation-threshold-rule.go | 48 +++- ...event-specficiation-threshold-rule_test.go | 244 +++++++++++++++--- .../custom-event-specficiations-api.go | 71 ++--- .../custom-event-specficiations-api_test.go | 103 ++++++-- ...ation-threshold-rule-condition-operator.go | 100 +++++++ ...-threshold-rule-condition-operator_test.go | 73 ++++++ 8 files changed, 533 insertions(+), 115 deletions(-) create mode 100644 instana/restapi/custom-event-specification-threshold-rule-condition-operator.go create mode 100644 instana/restapi/custom-event-specification-threshold-rule-condition-operator_test.go diff --git a/docs/resources/instana_custom_event_spec_threshold_rule.md b/docs/resources/instana_custom_event_spec_threshold_rule.md index 9fcab12..9480ca9 100644 --- a/docs/resources/instana_custom_event_spec_threshold_rule.md +++ b/docs/resources/instana_custom_event_spec_threshold_rule.md @@ -78,7 +78,7 @@ resource "instana_custom_event_spec_threshold_rule" "custom_health_metrics_unhea rule_metric_name = "metrics.gauges.myapp.healthIndicator" rule_window = 10000 rule_aggregation = "avg" - rule_condition_operator = "==" + rule_condition_operator = "=" rule_condition_value = 1 } ``` @@ -110,6 +110,7 @@ placeholder string. Allowed values: `is`, `contains`, `any`, `startsWith`, `end * `rule_aggregation` - Optional (depending on metric type) - the aggregation used to calculate the metric value for the given time window and/or rollup. Supported value: `sum`, `avg`, `min`, `max` * `rule_condition_operator` - Required - The condition operator used to check against the calculated metric value for the given -time window and/or rollup. Supported values: `==,` `!=,` `<=,` `<`, `>`, `=>` +time window and/or rollup. Supported values: `=` (`==` also supported as an alternative representation for equals), `!=`, `<=`, +`<`, `>`, `=>` * `rule_condition_value` - Required - The numeric condition value used to check against the calculated metric value for the given time window and/or rollup. \ No newline at end of file diff --git a/instana/resource-custom-event-specficiation-entity-verification-rule.go b/instana/resource-custom-event-specficiation-entity-verification-rule.go index 739fc96..1b67b7d 100644 --- a/instana/resource-custom-event-specficiation-entity-verification-rule.go +++ b/instana/resource-custom-event-specficiation-entity-verification-rule.go @@ -76,7 +76,7 @@ func NewCustomEventSpecificationWithEntityVerificationRuleResourceHandle() *Reso }, { Type: customEventSpecificationWithEntityVerificationRuleSchemaV2().CoreConfigSchema().ImpliedType(), - Upgrade: migrateCustomEventConfigWithThresholdRuleToVersion3ByChangingMatchingOperatorToInstanaRepresentation, + Upgrade: migrateCustomEventConfigWithEntityVerificationRuleToVersion3ByChangingMatchingOperatorToInstanaRepresentation, Version: 2, }, }, @@ -150,7 +150,7 @@ func customEventSpecificationWithEntityVerificationRuleSchemaV2() *schema.Resour } } -func migrateCustomEventConfigWithThresholdRuleToVersion3ByChangingMatchingOperatorToInstanaRepresentation(rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { +func migrateCustomEventConfigWithEntityVerificationRuleToVersion3ByChangingMatchingOperatorToInstanaRepresentation(rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { v, ok := rawState[EntityVerificationRuleFieldMatchingOperator] if ok { operator, err := restapi.SupportedMatchingOperators.FromTerraformValue(v.(string)) diff --git a/instana/resource-custom-event-specficiation-threshold-rule.go b/instana/resource-custom-event-specficiation-threshold-rule.go index 03edd97..c5b5c4e 100644 --- a/instana/resource-custom-event-specficiation-threshold-rule.go +++ b/instana/resource-custom-event-specficiation-threshold-rule.go @@ -69,8 +69,12 @@ var thresholdRuleSchemaFields = map[string]*schema.Schema{ ThresholdRuleFieldConditionOperator: { Type: schema.TypeString, Required: true, - ValidateFunc: validation.StringInSlice(restapi.SupportedConditionOperatorTypes.ToStringSlice(), false), - Description: "The condition operator (e.g >, <)", + ValidateFunc: validation.StringInSlice(restapi.SupportedConditionOperators.TerrafromSupportedValues(), false), + StateFunc: func(val interface{}) string { + operator, _ := restapi.SupportedConditionOperators.FromTerraformValue(val.(string)) + return operator.InstanaAPIValue() + }, + Description: "The condition operator (e.g >, <)", }, ThresholdRuleFieldConditionValue: { Type: schema.TypeFloat, @@ -109,7 +113,7 @@ func NewCustomEventSpecificationWithThresholdRuleResourceHandle() *ResourceHandl return &ResourceHandle{ ResourceName: ResourceInstanaCustomEventSpecificationThresholdRule, Schema: mergeSchemaMap(defaultCustomEventSchemaFields, thresholdRuleSchemaFields), - SchemaVersion: 2, + SchemaVersion: 3, StateUpgraders: []schema.StateUpgrader{ { Type: customEventSpecificationWithThresholdRuleSchemaV0().CoreConfigSchema().ImpliedType(), @@ -121,6 +125,11 @@ func NewCustomEventSpecificationWithThresholdRuleResourceHandle() *ResourceHandl Upgrade: migrateCustomEventConfigFullStateFromV1toV2AndRemoveDownstreamConfiguration, Version: 1, }, + { + Type: customEventSpecificationWithThresholdRuleSchemaV2().CoreConfigSchema().ImpliedType(), + Upgrade: migrateCustomEventConfigWithThreasholdRuleToVersion3ByChangingConditionOperatorToInstanaRepresentation, + Version: 2, + }, }, RestResourceFactory: func(api restapi.InstanaAPI) restapi.RestResource { return api.CustomEventSpecifications() }, UpdateState: updateStateForCustomEventSpecificationWithThresholdRule, @@ -136,6 +145,10 @@ func updateStateForCustomEventSpecificationWithThresholdRule(d *schema.ResourceD if err != nil { return err } + conditionOperator, err := ruleSpec.ConditionOperatorType() + if err != nil { + return err + } updateStateForBasicCustomEventSpecification(d, customEventSpecification) d.Set(CustomEventSpecificationRuleSeverity, severity) @@ -143,7 +156,7 @@ func updateStateForCustomEventSpecificationWithThresholdRule(d *schema.ResourceD d.Set(ThresholdRuleFieldRollup, ruleSpec.Rollup) d.Set(ThresholdRuleFieldWindow, ruleSpec.Window) d.Set(ThresholdRuleFieldAggregation, ruleSpec.Aggregation) - d.Set(ThresholdRuleFieldConditionOperator, ruleSpec.ConditionOperator) + d.Set(ThresholdRuleFieldConditionOperator, conditionOperator.InstanaAPIValue()) d.Set(ThresholdRuleFieldConditionValue, ruleSpec.ConditionValue) if ruleSpec.MetricPattern != nil { @@ -161,7 +174,12 @@ func mapStateToDataObjectForCustomEventSpecificationWithThresholdRule(d *schema. return restapi.CustomEventSpecification{}, err } metricName := d.Get(ThresholdRuleFieldMetricName).(string) - conditionOperator := restapi.ConditionOperatorType(d.Get(ThresholdRuleFieldConditionOperator).(string)) + conditionOperatorString := d.Get(ThresholdRuleFieldConditionOperator).(string) + conditionOperator, err := restapi.SupportedConditionOperators.FromTerraformValue(conditionOperatorString) + if err != nil { + return restapi.CustomEventSpecification{}, err + } + conditionOperatorInstanaValue := conditionOperator.InstanaAPIValue() rule := restapi.RuleSpecification{ DType: restapi.ThresholdRuleType, @@ -170,7 +188,7 @@ func mapStateToDataObjectForCustomEventSpecificationWithThresholdRule(d *schema. Rollup: GetIntPointerFromResourceData(d, ThresholdRuleFieldRollup), Window: GetIntPointerFromResourceData(d, ThresholdRuleFieldWindow), Aggregation: getAggregationTypePointerFromResourceData(d, ThresholdRuleFieldAggregation), - ConditionOperator: &conditionOperator, + ConditionOperator: &conditionOperatorInstanaValue, ConditionValue: GetFloat64PointerFromResourceData(d, ThresholdRuleFieldConditionValue), } @@ -210,3 +228,21 @@ func customEventSpecificationWithThresholdRuleSchemaV1() *schema.Resource { Schema: mergeSchemaMap(defaultCustomEventSchemaFieldsV1, thresholdRuleSchemaFields), } } + +func customEventSpecificationWithThresholdRuleSchemaV2() *schema.Resource { + return &schema.Resource{ + Schema: mergeSchemaMap(defaultCustomEventSchemaFieldsV1, thresholdRuleSchemaFields), + } +} + +func migrateCustomEventConfigWithThreasholdRuleToVersion3ByChangingConditionOperatorToInstanaRepresentation(rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + v, ok := rawState[ThresholdRuleFieldConditionOperator] + if ok { + operator, err := restapi.SupportedConditionOperators.FromTerraformValue(v.(string)) + if err != nil { + return rawState, err + } + rawState[ThresholdRuleFieldConditionOperator] = operator.InstanaAPIValue() + } + return rawState, nil +} diff --git a/instana/resource-custom-event-specficiation-threshold-rule_test.go b/instana/resource-custom-event-specficiation-threshold-rule_test.go index fc3064a..4e87f65 100644 --- a/instana/resource-custom-event-specficiation-threshold-rule_test.go +++ b/instana/resource-custom-event-specficiation-threshold-rule_test.go @@ -42,7 +42,7 @@ resource "instana_custom_event_spec_threshold_rule" "example" { rule_severity = "warning" rule_metric_name = "metric_name" rule_rollup = "40000" - rule_condition_operator = "==" + rule_condition_operator = "=" rule_condition_value = "1.2" } ` @@ -67,11 +67,36 @@ resource "instana_custom_event_spec_threshold_rule" "example" { rule_metric_name = "metric_name" rule_window = 60000 rule_aggregation = "sum" - rule_condition_operator = "==" + rule_condition_operator = "=" rule_condition_value = 1.2 } ` +const resourceCustomEventSpecificationWithThresholdRuleAndWindowAndAlternativeConditionOperatorRepresentationDefinitionTemplate = ` +provider "instana" { + api_token = "test-token" + endpoint = "localhost:{{PORT}}" + default_name_prefix = "prefix" + default_name_suffix = "suffix" + } + + resource "instana_custom_event_spec_threshold_rule" "example" { + name = "name {{ITERATION}}" + entity_type = "entity_type" + query = "query" + enabled = true + triggering = true + description = "description" + expiration_time = 60000 + rule_severity = "warning" + rule_metric_name = "metric_name" + rule_window = 60000 + rule_aggregation = "sum" + rule_condition_operator = "==" + rule_condition_value = 1.2 + } +` + const resourceCustomEventSpecificationWithThresholdRuleAndMetricPatternDefinitionTemplate = ` provider "instana" { api_token = "test-token" @@ -91,7 +116,7 @@ resource "instana_custom_event_spec_threshold_rule" "example" { rule_severity = "warning" rule_window = 60000 rule_aggregation = "sum" - rule_condition_operator = "==" + rule_condition_operator = "=" rule_condition_value = 1.2 rule_metric_pattern_prefix = "prefix" rule_metric_pattern_postfix = "postfix" @@ -104,37 +129,36 @@ const ( customEventSpecificationWithThresholdRuleApiPath = restapi.CustomEventSpecificationResourcePath + "/{id}" testCustomEventSpecificationWithThresholdRuleDefinition = "instana_custom_event_spec_threshold_rule.example" - customEventSpecificationWithThresholdRuleID = "custom-system-event-id" - customEventSpecificationWithThresholdRuleName = "name" - customEventSpecificationWithThresholdRuleEntityType = "entity_type" - customEventSpecificationWithThresholdRuleQuery = "query" - customEventSpecificationWithThresholdRuleExpirationTime = 60000 - customEventSpecificationWithThresholdRuleDescription = "description" - customEventSpecificationWithThresholdRuleMetricName = "metric_name" - customEventSpecificationWithThresholdRuleRollup = 40000 - customEventSpecificationWithThresholdRuleWindow = 60000 - customEventSpecificationWithThresholdRuleAggregation = restapi.AggregationSum - customEventSpecificationWithThresholdRuleConditionOperator = restapi.ConditionOperatorEquals - customEventSpecificationWithThresholdRuleConditionValue = float64(1.2) + customEventSpecificationWithThresholdRuleID = "custom-system-event-id" + customEventSpecificationWithThresholdRuleName = "name" + customEventSpecificationWithThresholdRuleEntityType = "entity_type" + customEventSpecificationWithThresholdRuleQuery = "query" + customEventSpecificationWithThresholdRuleExpirationTime = 60000 + customEventSpecificationWithThresholdRuleDescription = "description" + customEventSpecificationWithThresholdRuleMetricName = "metric_name" + customEventSpecificationWithThresholdRuleRollup = 40000 + customEventSpecificationWithThresholdRuleWindow = 60000 + customEventSpecificationWithThresholdRuleAggregation = restapi.AggregationSum + customEventSpecificationWithThresholdRuleConditionValue = float64(1.2) ) var CustomEventSpecificationWithThresholdRuleRuleSeverity = restapi.SeverityWarning.GetTerraformRepresentation() func TestCRUDOfCustomEventSpecificationWithThresholdRuleWithRollupResourceWithMockServer(t *testing.T) { - ruleAsJson := `{ "ruleType" : "threshold", "severity" : 5, "metricName" : "metric_name", "rollup" : 40000, "conditionOperator" : "==", "conditionValue" : 1.2 }` + ruleAsJson := `{ "ruleType" : "threshold", "severity" : 5, "metricName" : "metric_name", "rollup" : 40000, "conditionOperator" : "=", "conditionValue" : 1.2 }` testCRUDOfResourceCustomEventSpecificationThresholdRuleResourceWithMockServer( t, resourceCustomEventSpecificationWithThresholdRuleAndRollupDefinitionTemplate, ruleAsJson, resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldMetricName, customEventSpecificationWithThresholdRuleMetricName), resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldRollup, strconv.FormatInt(customEventSpecificationWithThresholdRuleRollup, 10)), - resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldConditionOperator, string(customEventSpecificationWithThresholdRuleConditionOperator)), + resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldConditionOperator, string(restapi.ConditionOperatorEquals.InstanaAPIValue())), resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldConditionValue, "1.2"), ) } func TestCRUDOfCustomEventSpecificationWithThresholdRuleWithWindowResourceWithMockServer(t *testing.T) { - ruleAsJson := `{ "ruleType" : "threshold", "severity" : 5, "metricName": "metric_name", "window" : 60000, "aggregation": "sum", "conditionOperator" : "==", "conditionValue" : 1.2 }` + ruleAsJson := `{ "ruleType" : "threshold", "severity" : 5, "metricName": "metric_name", "window" : 60000, "aggregation": "sum", "conditionOperator" : "=", "conditionValue" : 1.2 }` testCRUDOfResourceCustomEventSpecificationThresholdRuleResourceWithMockServer( t, resourceCustomEventSpecificationWithThresholdRuleAndWindowDefinitionTemplate, @@ -142,20 +166,34 @@ func TestCRUDOfCustomEventSpecificationWithThresholdRuleWithWindowResourceWithMo resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldMetricName, customEventSpecificationWithThresholdRuleMetricName), resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldWindow, strconv.FormatInt(customEventSpecificationWithThresholdRuleWindow, 10)), resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldAggregation, string(customEventSpecificationWithThresholdRuleAggregation)), - resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldConditionOperator, string(customEventSpecificationWithThresholdRuleConditionOperator)), + resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldConditionOperator, string(restapi.ConditionOperatorEquals.InstanaAPIValue())), + resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldConditionValue, "1.2"), + ) +} + +func TestCRUDOfCustomEventSpecificationWithThresholdRuleWithWindowAndAlternativeConditionOperatorRepresentationResourceWithMockServer(t *testing.T) { + ruleAsJson := `{ "ruleType" : "threshold", "severity" : 5, "metricName": "metric_name", "window" : 60000, "aggregation": "sum", "conditionOperator" : "=", "conditionValue" : 1.2 }` + testCRUDOfResourceCustomEventSpecificationThresholdRuleResourceWithMockServer( + t, + resourceCustomEventSpecificationWithThresholdRuleAndWindowAndAlternativeConditionOperatorRepresentationDefinitionTemplate, + ruleAsJson, + resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldMetricName, customEventSpecificationWithThresholdRuleMetricName), + resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldWindow, strconv.FormatInt(customEventSpecificationWithThresholdRuleWindow, 10)), + resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldAggregation, string(customEventSpecificationWithThresholdRuleAggregation)), + resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldConditionOperator, string(restapi.ConditionOperatorEquals.InstanaAPIValue())), resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldConditionValue, "1.2"), ) } func TestCRUDOfCustomEventSpecificationWithThresholdRuleWithMetricPatternResourceWithMockServer(t *testing.T) { - ruleAsJson := `{ "ruleType" : "threshold", "severity" : 5, "window" : 60000, "aggregation": "sum", "conditionOperator" : "==", "conditionValue" : 1.2, "metricPattern" : { "prefix" : "prefix", "postfix" : "postfix", "placeholder" : "placeholder", "operator" : "startsWith" } }` + ruleAsJson := `{ "ruleType" : "threshold", "severity" : 5, "window" : 60000, "aggregation": "sum", "conditionOperator" : "=", "conditionValue" : 1.2, "metricPattern" : { "prefix" : "prefix", "postfix" : "postfix", "placeholder" : "placeholder", "operator" : "startsWith" } }` testCRUDOfResourceCustomEventSpecificationThresholdRuleResourceWithMockServer( t, resourceCustomEventSpecificationWithThresholdRuleAndMetricPatternDefinitionTemplate, ruleAsJson, resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldWindow, strconv.FormatInt(customEventSpecificationWithThresholdRuleWindow, 10)), resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldAggregation, string(customEventSpecificationWithThresholdRuleAggregation)), - resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldConditionOperator, string(customEventSpecificationWithThresholdRuleConditionOperator)), + resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldConditionOperator, string(restapi.ConditionOperatorEquals.InstanaAPIValue())), resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldConditionValue, "1.2"), resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldMetricPatternPrefix, "prefix"), resource.TestCheckResourceAttr(testCustomEventSpecificationWithThresholdRuleDefinition, ThresholdRuleFieldMetricPatternPostfix, "postfix"), @@ -256,16 +294,17 @@ func TestCustomEventSpecificationWithThresholdRuleSchemaDefinitionIsValid(t *tes schemaAssert.AssertSchemaIsOptionalAndOfTypeString(ThresholdRuleFieldMetricPatternOperator) } -func TestCustomEventSpecificationWithThresholdRuleResourceShouldHaveSchemaVersionTwo(t *testing.T) { - assert.Equal(t, 2, NewCustomEventSpecificationWithThresholdRuleResourceHandle().SchemaVersion) +func TestCustomEventSpecificationWithThresholdRuleResourceShouldHaveSchemaVersionThree(t *testing.T) { + assert.Equal(t, 3, NewCustomEventSpecificationWithThresholdRuleResourceHandle().SchemaVersion) } -func TestCustomEventSpecificationWithThresholdRuleShouldHaveTwoStateUpgraderForVersionZeroAndOne(t *testing.T) { +func TestCustomEventSpecificationWithThresholdRuleShouldHaveThreeStateUpgraderForVersionZeroAndOneAndTwo(t *testing.T) { resourceHandler := NewCustomEventSpecificationWithThresholdRuleResourceHandle() - assert.Equal(t, 2, len(resourceHandler.StateUpgraders)) + assert.Equal(t, 3, len(resourceHandler.StateUpgraders)) assert.Equal(t, 0, resourceHandler.StateUpgraders[0].Version) assert.Equal(t, 1, resourceHandler.StateUpgraders[1].Version) + assert.Equal(t, 2, resourceHandler.StateUpgraders[2].Version) } func TestShouldMigrateCustomEventSpecificationWithThresholdRuleStateAndAddFullNameWithSameValueAsNameWhenMigratingFromVersion0To1(t *testing.T) { @@ -314,6 +353,49 @@ func TestShouldMigrateCustomEventSpecificationWithThresholdRuleStateToVersion2Wh assert.Nil(t, result["downstream_broadcast_to_all_alerting_configs"]) } +func TestShouldMigrateCustomEventSpecificationWithThresholdRuleStateToVersion3WhenConditionOperatorIsDefinedAndValid(t *testing.T) { + for _, op := range restapi.SupportedConditionOperators { + for _, v := range op.TerraformSupportedValues() { + t.Run(fmt.Sprintf("TestShouldMigrateCustomEventSpecificationWithThresholdRuleStateToVersion3WhenConditionOperatorIsDefinedAndValid%s", v), createTestCaseForSuccessfulMigrationOfCustomEventSpecificationWithThresholdRuleToVersion3(op, v)) + } + } +} + +func createTestCaseForSuccessfulMigrationOfCustomEventSpecificationWithThresholdRuleToVersion3(mo restapi.ConditionOperator, value string) func(*testing.T) { + return func(t *testing.T) { + rawData := make(map[string]interface{}) + rawData[ThresholdRuleFieldConditionOperator] = value + meta := "dummy" + + result, err := NewCustomEventSpecificationWithThresholdRuleResourceHandle().StateUpgraders[2].Upgrade(rawData, meta) + + assert.Nil(t, err) + assert.Equal(t, mo.InstanaAPIValue(), result[ThresholdRuleFieldConditionOperator]) + } +} + +func TestShouldDoNothingWhenMigratingCustomEventSpecificationWithThresholdRuleToVersion3AndNoConditionOperatorIsDefined(t *testing.T) { + rawData := make(map[string]interface{}) + meta := "dummy" + + result, err := NewCustomEventSpecificationWithThresholdRuleResourceHandle().StateUpgraders[2].Upgrade(rawData, meta) + + assert.Nil(t, err) + assert.Nil(t, result[ThresholdRuleFieldConditionOperator]) +} + +func TestShouldReturnErrorWhenCustomEventSpecificationWithThresholdRuleCannotBeMigratedToVersion3BecuaseOfUnsupportedConditionOperatorInState(t *testing.T) { + rawData := make(map[string]interface{}) + rawData[ThresholdRuleFieldConditionOperator] = "invalid" + meta := "dummy" + + result, err := NewCustomEventSpecificationWithThresholdRuleResourceHandle().StateUpgraders[2].Upgrade(rawData, meta) + + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "not a supported condition operator") + assert.Equal(t, rawData, result) +} + func TestShouldReturnCorrectResourceNameForCustomEventSpecificationWithThresholdRuleResource(t *testing.T) { name := NewCustomEventSpecificationWithThresholdRuleResourceHandle().ResourceName @@ -362,7 +444,7 @@ func testMappingOfCustomEventSpecificationWithThresholdRuleTerraformDataModelToS aggregation := customEventSpecificationWithThresholdRuleAggregation conditionValue := customEventSpecificationWithThresholdRuleConditionValue metricName := customEventSpecificationWithThresholdRuleMetricName - conditionOperator := customEventSpecificationWithThresholdRuleConditionOperator + conditionOperator := restapi.ConditionOperatorEquals.InstanaAPIValue() spec := restapi.CustomEventSpecification{ ID: customEventSpecificationWithThresholdRuleID, @@ -413,6 +495,96 @@ func testMappingOfCustomEventSpecificationWithThresholdRuleTerraformDataModelToS additionalAsserts(resourceData) } +func TestShouldFailToUpdateTerraformStateForCustomEventSpecificationWithThresholdRuleWhenSeverityIsNotSupported(t *testing.T) { + description := customEventSpecificationWithThresholdRuleDescription + expirationTime := customEventSpecificationWithThresholdRuleExpirationTime + query := customEventSpecificationWithThresholdRuleQuery + + window := customEventSpecificationWithThresholdRuleWindow + rollup := customEventSpecificationWithThresholdRuleRollup + aggregation := customEventSpecificationWithThresholdRuleAggregation + conditionValue := customEventSpecificationWithThresholdRuleConditionValue + metricName := customEventSpecificationWithThresholdRuleMetricName + conditionOperator := "invalid" + + spec := restapi.CustomEventSpecification{ + ID: customEventSpecificationWithThresholdRuleID, + Name: customEventSpecificationWithThresholdRuleName, + EntityType: customEventSpecificationWithThresholdRuleEntityType, + Query: &query, + Description: &description, + ExpirationTime: &expirationTime, + Triggering: true, + Enabled: true, + Rules: []restapi.RuleSpecification{ + { + DType: restapi.ThresholdRuleType, + Severity: 123, + MetricName: &metricName, + Window: &window, + Rollup: &rollup, + Aggregation: &aggregation, + ConditionOperator: &conditionOperator, + ConditionValue: &conditionValue, + }, + }, + } + + testHelper := NewTestHelper(t) + sut := NewCustomEventSpecificationWithThresholdRuleResourceHandle() + resourceData := testHelper.CreateEmptyResourceDataForResourceHandle(sut) + + err := sut.UpdateState(resourceData, spec) + + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "is not a valid severity") +} + +func TestShouldFailToUpdateTerraformStateForCustomEventSpecificationWithThresholdRuleWhenConditionOperatorTypeIsNotSupported(t *testing.T) { + description := customEventSpecificationWithThresholdRuleDescription + expirationTime := customEventSpecificationWithThresholdRuleExpirationTime + query := customEventSpecificationWithThresholdRuleQuery + + window := customEventSpecificationWithThresholdRuleWindow + rollup := customEventSpecificationWithThresholdRuleRollup + aggregation := customEventSpecificationWithThresholdRuleAggregation + conditionValue := customEventSpecificationWithThresholdRuleConditionValue + metricName := customEventSpecificationWithThresholdRuleMetricName + conditionOperator := "invalid" + + spec := restapi.CustomEventSpecification{ + ID: customEventSpecificationWithThresholdRuleID, + Name: customEventSpecificationWithThresholdRuleName, + EntityType: customEventSpecificationWithThresholdRuleEntityType, + Query: &query, + Description: &description, + ExpirationTime: &expirationTime, + Triggering: true, + Enabled: true, + Rules: []restapi.RuleSpecification{ + { + DType: restapi.ThresholdRuleType, + Severity: restapi.SeverityWarning.GetAPIRepresentation(), + MetricName: &metricName, + Window: &window, + Rollup: &rollup, + Aggregation: &aggregation, + ConditionOperator: &conditionOperator, + ConditionValue: &conditionValue, + }, + }, + } + + testHelper := NewTestHelper(t) + sut := NewCustomEventSpecificationWithThresholdRuleResourceHandle() + resourceData := testHelper.CreateEmptyResourceDataForResourceHandle(sut) + + err := sut.UpdateState(resourceData, spec) + + assert.NotNil(t, err) + assert.Contains(t, err.Error(), "invalid is not a supported condition operator") +} + func TestShouldSuccessfullyConvertCustomEventSpecificationWithThresholdRuleStateToDataModel(t *testing.T) { testMappingOfCustomEventSpecificationWithThresholdRuleTerraformStateToDataModel(t, func(resourceData *schema.ResourceData) { /* Default testcase without additional fields =< no additional mappings */ }, func(spec restapi.CustomEventSpecification) { /* Default testcase without additional fields => no additional asserts */ @@ -462,7 +634,7 @@ func testMappingOfCustomEventSpecificationWithThresholdRuleTerraformStateToDataM resourceData.Set(ThresholdRuleFieldWindow, customEventSpecificationWithThresholdRuleWindow) resourceData.Set(ThresholdRuleFieldRollup, customEventSpecificationWithThresholdRuleRollup) resourceData.Set(ThresholdRuleFieldAggregation, customEventSpecificationWithThresholdRuleAggregation) - resourceData.Set(ThresholdRuleFieldConditionOperator, customEventSpecificationWithThresholdRuleConditionOperator) + resourceData.Set(ThresholdRuleFieldConditionOperator, restapi.ConditionOperatorEquals.InstanaAPIValue()) resourceData.Set(ThresholdRuleFieldConditionValue, customEventSpecificationWithThresholdRuleConditionValue) result, err := resourceHandle.MapStateToDataObject(resourceData, utils.NewResourceNameFormatter("prefix ", " suffix")) @@ -484,7 +656,7 @@ func testMappingOfCustomEventSpecificationWithThresholdRuleTerraformStateToDataM assert.Equal(t, customEventSpecificationWithThresholdRuleWindow, *customEventSpec.Rules[0].Window) assert.Equal(t, customEventSpecificationWithThresholdRuleRollup, *customEventSpec.Rules[0].Rollup) assert.Equal(t, customEventSpecificationWithThresholdRuleAggregation, *customEventSpec.Rules[0].Aggregation) - assert.Equal(t, customEventSpecificationWithThresholdRuleConditionOperator, *customEventSpec.Rules[0].ConditionOperator) + assert.Equal(t, restapi.ConditionOperatorEquals.InstanaAPIValue(), *customEventSpec.Rules[0].ConditionOperator) assert.Equal(t, customEventSpecificationWithThresholdRuleConditionValue, *customEventSpec.Rules[0].ConditionValue) assert.Equal(t, restapi.SeverityWarning.GetAPIRepresentation(), customEventSpec.Rules[0].Severity) } @@ -498,5 +670,19 @@ func TestShouldFailToConvertCustomEventSpecificationWithThresholdRuleStateToData _, err := resourceHandle.MapStateToDataObject(resourceData, utils.NewResourceNameFormatter("prefix ", " suffix")) - assert.NotNil(t, err) + assert.Error(t, err) +} + +func TestShouldFailToConvertCustomEventSpecificationWithThresholdRuleStateToDataModelWhenConditionOperationIsNotSupported(t *testing.T) { + testHelper := NewTestHelper(t) + resourceHandle := NewCustomEventSpecificationWithThresholdRuleResourceHandle() + + resourceData := testHelper.CreateEmptyResourceDataForResourceHandle(resourceHandle) + resourceData.Set(CustomEventSpecificationRuleSeverity, restapi.SeverityWarning.GetTerraformRepresentation()) + resourceData.Set(ThresholdRuleFieldConditionOperator, "invalid") + + _, err := resourceHandle.MapStateToDataObject(resourceData, utils.NewResourceNameFormatter("prefix ", " suffix")) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "is not a supported condition operator of the Instana Terraform provider") } diff --git a/instana/restapi/custom-event-specficiations-api.go b/instana/restapi/custom-event-specficiations-api.go index b53767f..66e605e 100644 --- a/instana/restapi/custom-event-specficiations-api.go +++ b/instana/restapi/custom-event-specficiations-api.go @@ -82,49 +82,6 @@ func IsSupportedAggregationType(aggregation AggregationType) bool { return false } -//ConditionOperatorType custom type representing a condition operator of a custom event specification rule -type ConditionOperatorType string - -//ConditionOperatorTypes custom type representing a slice of ConditionOperatorType -type ConditionOperatorTypes []ConditionOperatorType - -//ToStringSlice Returns the string representations of the condition operators -func (types ConditionOperatorTypes) ToStringSlice() []string { - result := make([]string, len(types)) - for i, v := range types { - result[i] = string(v) - } - return result -} - -const ( - //ConditionOperatorEquals const for a equals (==) condition operator - ConditionOperatorEquals = ConditionOperatorType("==") - //ConditionOperatorNotEqual const for a not equal (!=) condition operator - ConditionOperatorNotEqual = ConditionOperatorType("!=") - //ConditionOperatorLessThan const for a less than (<) condition operator - ConditionOperatorLessThan = ConditionOperatorType("<") - //ConditionOperatorLessThanOrEqual const for a less than or equal (<=) condition operator - ConditionOperatorLessThanOrEqual = ConditionOperatorType("<=") - //ConditionOperatorGreaterThan const for a greater than (>) condition operator - ConditionOperatorGreaterThan = ConditionOperatorType(">") - //ConditionOperatorGreaterThanOrEqual const for a greater than or equal (<=) condition operator - ConditionOperatorGreaterThanOrEqual = ConditionOperatorType(">=") -) - -//SupportedConditionOperatorTypes slice of supported aggregation types -var SupportedConditionOperatorTypes = ConditionOperatorTypes{ConditionOperatorEquals, ConditionOperatorNotEqual, ConditionOperatorLessThan, ConditionOperatorLessThanOrEqual, ConditionOperatorGreaterThan, ConditionOperatorGreaterThanOrEqual} - -//IsSupportedConditionOperatorType check if the provided condition operator type is supported -func IsSupportedConditionOperatorType(operator ConditionOperatorType) bool { - for _, v := range SupportedConditionOperatorTypes { - if v == operator { - return true - } - } - return false -} - //MetricPatternOperatorType the operator type of the metric pattern of a dynamic built-in metric type MetricPatternOperatorType string @@ -217,13 +174,13 @@ type RuleSpecification struct { SystemRuleID *string `json:"systemRuleId"` //Threshold Rule fields - MetricName *string `json:"metricName"` - Rollup *int `json:"rollup"` - Window *int `json:"window"` - Aggregation *AggregationType `json:"aggregation"` - ConditionOperator *ConditionOperatorType `json:"conditionOperator"` - ConditionValue *float64 `json:"conditionValue"` - MetricPattern *MetricPattern `json:"metricPattern"` + MetricName *string `json:"metricName"` + Rollup *int `json:"rollup"` + Window *int `json:"window"` + Aggregation *AggregationType `json:"aggregation"` + ConditionOperator *string `json:"conditionOperator"` + ConditionValue *float64 `json:"conditionValue"` + MetricPattern *MetricPattern `json:"metricPattern"` //Entity Verification Rule MatchingEntityType *string `json:"matchingEntityType"` @@ -232,6 +189,18 @@ type RuleSpecification struct { OfflineDuration *int `json:"offlineDuration"` } +//ConditionOperatorType returns the ConditionOperator for the given Instana Web REST API representation when available. In case of invalid values an error will be returned +func (r *RuleSpecification) ConditionOperatorType() (ConditionOperator, error) { + if r.ConditionOperator != nil { + operator, err := SupportedConditionOperators.FromInstanaAPIValue(*r.ConditionOperator) + if err != nil { + return nil, err + } + return operator, nil + } + return nil, nil +} + //MatchingOperatorType returns the MatchingOperatorType for the given Instana Web REST API representation when available. In case of invalid values an error will be returned func (r *RuleSpecification) MatchingOperatorType() (MatchingOperator, error) { if r.MatchingOperator != nil { @@ -278,7 +247,7 @@ func (r *RuleSpecification) validateThresholdRule() error { return errors.New("aggregation type of threshold rule is mission or not valid") } - if r.ConditionOperator == nil || !IsSupportedConditionOperatorType(*r.ConditionOperator) { + if r.ConditionOperator == nil || !SupportedConditionOperators.IsSupportedInstanaAPIConditionOperator(*r.ConditionOperator) { return errors.New("condition operator of threshold rule is missing or not valid") } if r.MetricPattern != nil { diff --git a/instana/restapi/custom-event-specficiations-api_test.go b/instana/restapi/custom-event-specficiations-api_test.go index f207cb6..7127495 100644 --- a/instana/restapi/custom-event-specficiations-api_test.go +++ b/instana/restapi/custom-event-specficiations-api_test.go @@ -20,7 +20,6 @@ const ( customEventWindow = 60000 customEventRollup = 40000 customEventAggregation = AggregationSum - customEventConditionOperator = ConditionOperatorEquals customEventConditionValue = 1.2 customEventMetricPatternPrefix = "metric-pattern-prefix" @@ -229,7 +228,7 @@ func TestShouldFailToValidateSystemRuleWhenRuleTypeIsMissing(t *testing.T) { func TestShouldValidateFullThresholdRuleSpecificationWithWindowRollupAndAggregation(t *testing.T) { metricName := customEventMetricName aggregation := customEventAggregation - conditionOperator := customEventConditionOperator + conditionOperator := ConditionOperatorEquals.InstanaAPIValue() conditionValue := customEventConditionValue window := customEventWindow rollup := customEventRollup @@ -257,7 +256,7 @@ func TestShouldSuccessfullyValidateMinimalThresholdRuleSpecificationForAllSuppor func createTestCaseForSuccessfullValidateMinimalThresholdRuleForAggregation(aggregation AggregationType) func(*testing.T) { metricName := customEventMetricName - conditionOperator := customEventConditionOperator + conditionOperator := ConditionOperatorEquals.InstanaAPIValue() return func(t *testing.T) { conditionValue := customEventConditionValue window := customEventWindow @@ -278,15 +277,15 @@ func createTestCaseForSuccessfullValidateMinimalThresholdRuleForAggregation(aggr } func TestShouldSuccessfullyValidateMinimalThresholdRuleSpecificationForAllSupportedConditionOperators(t *testing.T) { - for _, o := range SupportedConditionOperatorTypes { + for _, o := range SupportedConditionOperators { t.Run(fmt.Sprintf("TestShouldSuccessfullyValidateMinimalThresholdRuleForConditionOperator%s", o), createTestCaseForSuccessfullValidateMinimalThresholdRuleForConditionOperators(o)) } } -func createTestCaseForSuccessfullValidateMinimalThresholdRuleForConditionOperators(operator ConditionOperatorType) func(*testing.T) { +func createTestCaseForSuccessfullValidateMinimalThresholdRuleForConditionOperators(operator ConditionOperator) func(*testing.T) { return func(t *testing.T) { metricName := customEventMetricName - conditionOperator := customEventConditionOperator + conditionOperator := operator.InstanaAPIValue() aggregation := customEventAggregation conditionValue := customEventConditionValue window := customEventWindow @@ -308,7 +307,7 @@ func createTestCaseForSuccessfullValidateMinimalThresholdRuleForConditionOperato func TestShouldValidateMinimalThresholdRuleSpecificationWithRollup(t *testing.T) { metricName := customEventMetricName - conditionOperator := customEventConditionOperator + conditionOperator := ConditionOperatorEquals.InstanaAPIValue() rollup := customEventRollup conditionValue := customEventConditionValue rule := RuleSpecification{ @@ -326,7 +325,7 @@ func TestShouldValidateMinimalThresholdRuleSpecificationWithRollup(t *testing.T) } func TestShouldFailToValidateThresholdRuleSpecificationWhenMetricNameandMetricPatternIsMissing(t *testing.T) { - conditionOperator := customEventConditionOperator + conditionOperator := ConditionOperatorEquals.InstanaAPIValue() aggregation := customEventAggregation conditionValue := customEventConditionValue window := customEventWindow @@ -347,7 +346,7 @@ func TestShouldFailToValidateThresholdRuleSpecificationWhenMetricNameandMetricPa func TestShouldFailToValidateThresholdRuleSpecificationWhenMetricNameIsBlankAndMetricPatternIsMissing(t *testing.T) { metricName := "" - conditionOperator := customEventConditionOperator + conditionOperator := ConditionOperatorEquals.InstanaAPIValue() aggregation := customEventAggregation conditionValue := customEventConditionValue window := customEventWindow @@ -369,7 +368,7 @@ func TestShouldFailToValidateThresholdRuleSpecificationWhenMetricNameIsBlankAndM func TestShouldFailToValidateThresholdRuleSpecificationWhenMetricNameAndMetricPatternAreDefined(t *testing.T) { metricName := "test" - conditionOperator := customEventConditionOperator + conditionOperator := ConditionOperatorEquals.InstanaAPIValue() aggregation := customEventAggregation conditionValue := customEventConditionValue window := customEventWindow @@ -393,7 +392,7 @@ func TestShouldFailToValidateThresholdRuleSpecificationWhenMetricNameAndMetricPa func TestShouldFailToValidateThresholdRuleSpecificationWhenNeitherRollupNorWindowIsDefined(t *testing.T) { metricName := customEventMetricName - conditionOperator := customEventConditionOperator + conditionOperator := ConditionOperatorEquals.InstanaAPIValue() aggregation := customEventAggregation conditionValue := customEventConditionValue rule := RuleSpecification{ @@ -413,7 +412,7 @@ func TestShouldFailToValidateThresholdRuleSpecificationWhenNeitherRollupNorWindo func TestShouldFailToValidateThresholdRuleSpecificationWithRollupAndWindowAreZero(t *testing.T) { metricName := customEventMetricName - conditionOperator := customEventConditionOperator + conditionOperator := ConditionOperatorEquals.InstanaAPIValue() window := 0 rollup := 0 aggregation := customEventAggregation @@ -437,7 +436,7 @@ func TestShouldFailToValidateThresholdRuleSpecificationWithRollupAndWindowAreZer func TestShouldFailToValidateThresholdRuleSpecificationWithWindowWhenAggregationIsMissingConditionOperator(t *testing.T) { metricName := customEventMetricName - conditionOperator := customEventConditionOperator + conditionOperator := ConditionOperatorEquals.InstanaAPIValue() conditionValue := customEventConditionValue window := customEventWindow rule := RuleSpecification{ @@ -457,7 +456,7 @@ func TestShouldFailToValidateThresholdRuleSpecificationWithWindowWhenAggregation func TestShouldFailToValidateThresholdRuleSpecificationWithWindowWhenAggregationIsNotValid(t *testing.T) { metricName := customEventMetricName - conditionOperator := customEventConditionOperator + conditionOperator := ConditionOperatorEquals.InstanaAPIValue() aggregation := AggregationType(valueInvalid) conditionValue := customEventConditionValue window := customEventWindow @@ -500,7 +499,7 @@ func TestShouldFailToValidateThresholdRuleSpecificationWithWindowWhenConditionOp func TestShouldFailToValidateThresholdRuleSpecificationWithWindowWhenConditionOperatorIsNotValid(t *testing.T) { metricName := customEventMetricName aggregation := customEventAggregation - conditionOperator := ConditionOperatorType(valueInvalid) + conditionOperator := "invalid" conditionValue := customEventConditionValue window := customEventWindow rule := RuleSpecification{ @@ -521,7 +520,7 @@ func TestShouldFailToValidateThresholdRuleSpecificationWithWindowWhenConditionOp func TestShouldSuccessfullyValidateThresholdRuleSpecificationWithMetricPattern(t *testing.T) { aggregation := customEventAggregation - conditionOperator := ConditionOperatorEquals + conditionOperator := ConditionOperatorEquals.InstanaAPIValue() conditionValue := customEventConditionValue window := customEventWindow metricPattern := MetricPattern{ @@ -545,7 +544,7 @@ func TestShouldSuccessfullyValidateThresholdRuleSpecificationWithMetricPattern(t func TestShouldFailToValidateThresholdRuleSpecificationWithMetricPatternWhenMetricPatternIsNotValid(t *testing.T) { aggregation := customEventAggregation - conditionOperator := ConditionOperatorEquals + conditionOperator := ConditionOperatorEquals.InstanaAPIValue() conditionValue := customEventConditionValue window := customEventWindow metricPattern := MetricPattern{ @@ -567,6 +566,67 @@ func TestShouldFailToValidateThresholdRuleSpecificationWithMetricPatternWhenMetr assert.Contains(t, err.Error(), messagePartMetricPatternPrefix) } +func TestShouldReturnConditionOperatorTypeOfThresholdRuleWhenValidInstanaWebRestAPIConditionOperatorTypoIsProvided(t *testing.T) { + metricName := customEventMetricName + conditionOperator := ConditionOperatorEquals.InstanaAPIValue() + rollup := customEventRollup + conditionValue := customEventConditionValue + rule := RuleSpecification{ + DType: ThresholdRuleType, + Severity: SeverityWarning.GetAPIRepresentation(), + MetricName: &metricName, + Rollup: &rollup, + ConditionOperator: &conditionOperator, + ConditionValue: &conditionValue, + } + + val, err := rule.ConditionOperatorType() + + assert.Nil(t, err) + assert.NotNil(t, val) + assert.Equal(t, ConditionOperatorEquals, val) +} + +func TestShouldReturnErrorWheConditionOperatorTypeOfThresholdnRuleIsNotAValidInstanaWebRestAPIValue(t *testing.T) { + metricName := customEventMetricName + conditionOperator := "invalid" + rollup := customEventRollup + conditionValue := customEventConditionValue + rule := RuleSpecification{ + DType: ThresholdRuleType, + Severity: SeverityWarning.GetAPIRepresentation(), + MetricName: &metricName, + Rollup: &rollup, + ConditionOperator: &conditionOperator, + ConditionValue: &conditionValue, + } + + val, err := rule.ConditionOperatorType() + + assert.NotNil(t, err) + assert.Nil(t, val) +} + +func TestShouldReturnNilWhenRuleSpecificationDoesNotSupportConditionOperatorTypesAndConditionOperatorTypeIsRequested(t *testing.T) { + entityLabel := customEventMatchingEntityLabel + entityType := customEventMatchingEntityType + operator := MatchingOperatorIs.InstanaAPIValue() + offlineDuration := customEventOfflineDuration + rule := RuleSpecification{ + DType: EntityVerificationRuleType, + Severity: SeverityWarning.GetAPIRepresentation(), + MatchingEntityLabel: &entityLabel, + MatchingEntityType: &entityType, + MatchingOperator: &operator, + OfflineDuration: &offlineDuration, + } + + val, err := rule.ConditionOperatorType() + + assert.Nil(t, err) + assert.Nil(t, val) +} + func TestShouldValidateEntityVerificationRuleSpecificationWhenAllRequiredFieldsAreProvided(t *testing.T) { entityLabel := customEventMatchingEntityLabel entityType := customEventMatchingEntityType @@ -629,7 +689,7 @@ func TestShouldReturnErrorWhenMatchingOperatorTypeForEntityVerificationRuleIsNot func TestShouldReturnNilWhenRuleSpecificationDoesNotSupportMatchingOperatorTypesAndMatchingOperatorTypeIsRequested(t *testing.T) { metricName := customEventMetricName - conditionOperator := customEventConditionOperator + conditionOperator := ConditionOperatorEquals.InstanaAPIValue() rollup := customEventRollup conditionValue := customEventConditionValue rule := RuleSpecification{ @@ -779,13 +839,6 @@ func TestShouldConvertSupportedAggregationTypesToSliceOfString(t *testing.T) { assert.Equal(t, expectedResult, result) } -func TestShouldConvertSupportedConditionOperatorTypesToSliceOfString(t *testing.T) { - expectedResult := []string{string(ConditionOperatorEquals), string(ConditionOperatorNotEqual), string(ConditionOperatorLessThan), string(ConditionOperatorLessThanOrEqual), string(ConditionOperatorGreaterThan), string(ConditionOperatorGreaterThanOrEqual)} - result := SupportedConditionOperatorTypes.ToStringSlice() - - assert.Equal(t, expectedResult, result) -} - func TestShouldReturnTrueForAllSupportedMetricPatternTypes(t *testing.T) { for _, ot := range SupportedMetricPatternOperatorTypes { t.Run(fmt.Sprintf("TestShouldReturnTrueForAllSupportedMetricPatternTypes%s", ot), createTestCaseForVerifyingIfAIsSupportedReturnsTrueForAllSupportedMetricPatternTypes(ot)) diff --git a/instana/restapi/custom-event-specification-threshold-rule-condition-operator.go b/instana/restapi/custom-event-specification-threshold-rule-condition-operator.go new file mode 100644 index 0000000..3abbea4 --- /dev/null +++ b/instana/restapi/custom-event-specification-threshold-rule-condition-operator.go @@ -0,0 +1,100 @@ +package restapi + +import "fmt" + +//ConditionOperator representation of a ConditionOperator of a threshold rule of a custom event specification of the Instana Web REST API +type ConditionOperator interface { + InstanaAPIValue() string + TerraformSupportedValues() []string +} + +func newBasicConditionOperator(instanaAPIValue string, additionalSupportedTerraformValues ...string) ConditionOperator { + return &baseConditionOperator{instanaAPIValue: instanaAPIValue, terraformSupportedValues: append(additionalSupportedTerraformValues, instanaAPIValue)} +} + +//ConditionOperatorType custom type representing a matching operator of a custom event specification rule +type baseConditionOperator struct { + instanaAPIValue string + terraformSupportedValues []string +} + +//InstanaAPIValue implementation of ConditionOperator interace +func (b *baseConditionOperator) InstanaAPIValue() string { + return b.instanaAPIValue +} + +//TerraformSupportedValues implementation of ConditionOperator interace +func (b *baseConditionOperator) TerraformSupportedValues() []string { + return b.terraformSupportedValues +} + +//ConditionOperators custom type representing a slice of ConditionOperatorType +type ConditionOperators []ConditionOperator + +//TerrafromSupportedValues Returns the terraform string representations fo the matching operators +func (types ConditionOperators) TerrafromSupportedValues() []string { + result := make([]string, 0) + for _, v := range types { + result = append(result, v.TerraformSupportedValues()...) + } + return result +} + +//InstanaAPISupportedValues Returns the terraform string representations fo the matching operators +func (types ConditionOperators) InstanaAPISupportedValues() []string { + result := make([]string, len(types)) + for i, v := range types { + result[i] = v.InstanaAPIValue() + } + return result +} + +//IsSupportedInstanaAPIConditionOperator check if the provided matching operator type is a supported instana api value +func (types ConditionOperators) IsSupportedInstanaAPIConditionOperator(operator string) bool { + for _, t := range types { + if t.InstanaAPIValue() == operator { + return true + } + } + return false +} + +//FromInstanaAPIValue returns the ConditionOperator for the given instana apistring value or an error if the operator type does not exist +func (types ConditionOperators) FromInstanaAPIValue(instanaAPIvalue string) (ConditionOperator, error) { + for _, t := range types { + if t.InstanaAPIValue() == instanaAPIvalue { + return t, nil + } + } + return ConditionOperatorEquals, fmt.Errorf("%s is not a supported condition operator of the Instana Web REST API", instanaAPIvalue) +} + +//FromTerraformValue returns the ConditionOperator for the given terraform string value or an error if the operator type does not exist +func (types ConditionOperators) FromTerraformValue(terraformRepresentation string) (ConditionOperator, error) { + for _, t := range types { + for _, v := range t.TerraformSupportedValues() { + if v == terraformRepresentation { + return t, nil + } + } + } + return ConditionOperatorEquals, fmt.Errorf("%s is not a supported condition operator of the Instana Terraform provider", terraformRepresentation) +} + +var ( + //ConditionOperatorEquals const for a equals (==) condition operator + ConditionOperatorEquals = newBasicConditionOperator("=", "==") + //ConditionOperatorNotEqual const for a not equal (!=) condition operator + ConditionOperatorNotEqual = newBasicConditionOperator("!=") + //ConditionOperatorLessThan const for a less than (<) condition operator + ConditionOperatorLessThan = newBasicConditionOperator("<") + //ConditionOperatorLessThanOrEqual const for a less than or equal (<=) condition operator + ConditionOperatorLessThanOrEqual = newBasicConditionOperator("<=") + //ConditionOperatorGreaterThan const for a greater than (>) condition operator + ConditionOperatorGreaterThan = newBasicConditionOperator(">") + //ConditionOperatorGreaterThanOrEqual const for a greater than or equal (<=) condition operator + ConditionOperatorGreaterThanOrEqual = newBasicConditionOperator(">=") +) + +//SupportedConditionOperators slice of supported matching operatorTypes types +var SupportedConditionOperators = ConditionOperators{ConditionOperatorEquals, ConditionOperatorNotEqual, ConditionOperatorLessThan, ConditionOperatorLessThanOrEqual, ConditionOperatorGreaterThan, ConditionOperatorGreaterThanOrEqual} diff --git a/instana/restapi/custom-event-specification-threshold-rule-condition-operator_test.go b/instana/restapi/custom-event-specification-threshold-rule-condition-operator_test.go new file mode 100644 index 0000000..2ae06a8 --- /dev/null +++ b/instana/restapi/custom-event-specification-threshold-rule-condition-operator_test.go @@ -0,0 +1,73 @@ +package restapi_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + + . "github.com/gessnerfl/terraform-provider-instana/instana/restapi" +) + +func TestShouldPovideInstanaSupportedValuesOfConditionOperatorTypes(t *testing.T) { + expectedResult := []string{ConditionOperatorEquals.InstanaAPIValue(), ConditionOperatorNotEqual.InstanaAPIValue(), ConditionOperatorLessThan.InstanaAPIValue(), ConditionOperatorLessThanOrEqual.InstanaAPIValue(), ConditionOperatorGreaterThan.InstanaAPIValue(), ConditionOperatorGreaterThanOrEqual.InstanaAPIValue()} + result := SupportedConditionOperators.InstanaAPISupportedValues() + + assert.Equal(t, expectedResult, result) +} + +func TestShouldPovideTerraformSupportedValuesOfConditionOperatorTypes(t *testing.T) { + expectedResult := []string{} + for _, op := range SupportedConditionOperators { + expectedResult = append(expectedResult, op.TerraformSupportedValues()...) + } + result := SupportedConditionOperators.TerrafromSupportedValues() + + assert.Equal(t, expectedResult, result) +} + +func TestShouldReturnTheConditionOperatorTypeForAllSupportedInstanaWebRestAPIValues(t *testing.T) { + for _, op := range SupportedConditionOperators { + t.Run(fmt.Sprintf("TestShouldReturnTheConditionOperatorTypeForAllSupportedInstanaWebRestAPIValues%s", op), createTestCaseForTestShouldReturnTheConditionOperatorTypeForAllSupportedInstanaWebRestAPIValues(op)) + } +} + +func createTestCaseForTestShouldReturnTheConditionOperatorTypeForAllSupportedInstanaWebRestAPIValues(op ConditionOperator) func(*testing.T) { + return func(t *testing.T) { + val, err := SupportedConditionOperators.FromInstanaAPIValue(op.InstanaAPIValue()) + + assert.Nil(t, err) + assert.Equal(t, op, val) + } +} + +func TestShouldReturnErrorWhenTheConditionOperatorTypeIsNotASupportedInstanaWebRestAPIValue(t *testing.T) { + val, err := SupportedConditionOperators.FromInstanaAPIValue("invalid") + + assert.NotNil(t, err) + assert.Equal(t, ConditionOperatorEquals, val) +} + +func TestShouldReturnTheConditionOperatorTypeForAllSupportedTerraformProviderValues(t *testing.T) { + for _, op := range SupportedConditionOperators { + for _, v := range op.TerraformSupportedValues() { + t.Run(fmt.Sprintf("TestShouldReturnTheConditionOperatorTypeForAllSupportedTerraformProviderValues%s", v), createTestCaseForTestShouldReturnTheConditionOperatorTypeForAllSupportedTerraformProviderValues(op, v)) + } + } +} + +func createTestCaseForTestShouldReturnTheConditionOperatorTypeForAllSupportedTerraformProviderValues(op ConditionOperator, value string) func(*testing.T) { + return func(t *testing.T) { + val, err := SupportedConditionOperators.FromTerraformValue(value) + + assert.Nil(t, err) + assert.Equal(t, op, val) + } +} + +func TestShouldReturnErrorWhenTheConditionOperatorTypeIsNotASupportedInstanaTerraformProviderValue(t *testing.T) { + val, err := SupportedConditionOperators.FromTerraformValue("invalid") + + assert.NotNil(t, err) + assert.Equal(t, ConditionOperatorEquals, val) +}