terraform-provider-stackitp.../stackit/internal/services/observability/alertgroup/resource_test.go
Mauritz Uphoff 289746c7d1
Implement observability alertgroups (#778)
* feat: implement observability alertgroups

* review changes
2025-04-14 13:21:30 +02:00

366 lines
9.5 KiB
Go

package alertgroup
import (
"context"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/utils"
"github.com/stackitcloud/stackit-sdk-go/services/observability"
)
func TestToCreatePayload(t *testing.T) {
tests := []struct {
name string
input *Model
expect *observability.CreateAlertgroupsPayload
expectErr bool
}{
{
name: "Nil Model",
input: nil,
expect: nil,
expectErr: true,
},
{
name: "Empty Model",
input: &Model{
Name: types.StringNull(),
Interval: types.StringNull(),
Rules: types.ListNull(types.StringType),
},
expect: &observability.CreateAlertgroupsPayload{},
expectErr: false,
},
{
name: "Model with Name and Interval",
input: &Model{
Name: types.StringValue("test-alertgroup"),
Interval: types.StringValue("5m"),
},
expect: &observability.CreateAlertgroupsPayload{
Name: utils.Ptr("test-alertgroup"),
Interval: utils.Ptr("5m"),
},
expectErr: false,
},
{
name: "Model with Full Information",
input: &Model{
Name: types.StringValue("full-alertgroup"),
Interval: types.StringValue("10m"),
Rules: types.ListValueMust(
types.ObjectType{AttrTypes: ruleTypes},
[]attr.Value{
types.ObjectValueMust(
ruleTypes,
map[string]attr.Value{
"alert": types.StringValue("alert"),
"expression": types.StringValue("expression"),
"for": types.StringValue("10s"),
"labels": types.MapValueMust(
types.StringType,
map[string]attr.Value{
"k": types.StringValue("v"),
},
),
"annotations": types.MapValueMust(
types.StringType,
map[string]attr.Value{
"k": types.StringValue("v"),
},
),
},
),
},
),
},
expect: &observability.CreateAlertgroupsPayload{
Name: utils.Ptr("full-alertgroup"),
Interval: utils.Ptr("10m"),
Rules: &[]observability.UpdateAlertgroupsRequestInnerRulesInner{
{
Alert: utils.Ptr("alert"),
Annotations: &map[string]interface{}{
"k": "v",
},
Expr: utils.Ptr("expression"),
For: utils.Ptr("10s"),
Labels: &map[string]interface{}{
"k": "v",
},
},
},
},
expectErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
got, err := toCreatePayload(ctx, tt.input)
if (err != nil) != tt.expectErr {
t.Fatalf("expected error: %v, got: %v", tt.expectErr, err)
}
if diff := cmp.Diff(got, tt.expect); diff != "" {
t.Errorf("unexpected result (-got +want):\n%s", diff)
}
})
}
}
func TestToRulesPayload(t *testing.T) {
tests := []struct {
name string
input *Model
expect []observability.UpdateAlertgroupsRequestInnerRulesInner
expectErr bool
}{
{
name: "Nil Rules",
input: &Model{
Rules: types.ListNull(types.StringType), // Simulates a lack of rules
},
expect: []observability.UpdateAlertgroupsRequestInnerRulesInner{},
expectErr: false,
},
{
name: "Invalid Rule Element Type",
input: &Model{
Rules: types.ListValueMust(types.StringType, []attr.Value{
types.StringValue("invalid"), // Should cause a conversion failure
}),
},
expect: nil,
expectErr: true,
},
{
name: "Single Valid Rule",
input: &Model{
Rules: types.ListValueMust(types.ObjectType{AttrTypes: ruleTypes}, []attr.Value{
types.ObjectValueMust(ruleTypes, map[string]attr.Value{
"alert": types.StringValue("alert"),
"expression": types.StringValue("expr"),
"for": types.StringValue("5s"),
"labels": types.MapValueMust(types.StringType, map[string]attr.Value{
"key": types.StringValue("value"),
}),
"annotations": types.MapValueMust(types.StringType, map[string]attr.Value{
"note": types.StringValue("important"),
}),
}),
}),
},
expect: []observability.UpdateAlertgroupsRequestInnerRulesInner{
{
Alert: utils.Ptr("alert"),
Expr: utils.Ptr("expr"),
For: utils.Ptr("5s"),
Labels: &map[string]interface{}{
"key": "value",
},
Annotations: &map[string]interface{}{
"note": "important",
},
},
},
expectErr: false,
},
{
name: "Multiple Valid Rules",
input: &Model{
Rules: types.ListValueMust(types.ObjectType{AttrTypes: ruleTypes}, []attr.Value{
types.ObjectValueMust(ruleTypes, map[string]attr.Value{
"alert": types.StringValue("alert1"),
"expression": types.StringValue("expr1"),
"for": types.StringValue("5s"),
"labels": types.MapNull(types.StringType),
"annotations": types.MapNull(types.StringType),
}),
types.ObjectValueMust(ruleTypes, map[string]attr.Value{
"alert": types.StringValue("alert2"),
"expression": types.StringValue("expr2"),
"for": types.StringValue("10s"),
"labels": types.MapValueMust(types.StringType, map[string]attr.Value{
"key": types.StringValue("value"),
}),
"annotations": types.MapValueMust(types.StringType, map[string]attr.Value{
"note": types.StringValue("important"),
}),
}),
}),
},
expect: []observability.UpdateAlertgroupsRequestInnerRulesInner{
{
Alert: utils.Ptr("alert1"),
Expr: utils.Ptr("expr1"),
For: utils.Ptr("5s"),
},
{
Alert: utils.Ptr("alert2"),
Expr: utils.Ptr("expr2"),
For: utils.Ptr("10s"),
Labels: &map[string]interface{}{
"key": "value",
},
Annotations: &map[string]interface{}{
"note": "important",
},
},
},
expectErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
got, err := toRulesPayload(ctx, tt.input)
if (err != nil) != tt.expectErr {
t.Fatalf("expected error: %v, got: %v", tt.expectErr, err)
}
if diff := cmp.Diff(got, tt.expect); diff != "" {
t.Errorf("unexpected result (-got +want):\n%s", diff)
}
})
}
}
func TestMapFields(t *testing.T) {
tests := []struct {
name string
alertGroup *observability.AlertGroup
model *Model
expectedName string
expectedID string
expectErr bool
}{
{
name: "Nil AlertGroup",
alertGroup: nil,
model: &Model{},
expectErr: true,
},
{
name: "Nil Model",
alertGroup: &observability.AlertGroup{},
model: nil,
expectErr: true,
},
{
name: "Interval Missing",
alertGroup: &observability.AlertGroup{
Name: utils.Ptr("alert-group-name"),
},
model: &Model{
Name: types.StringValue("alert-group-name"),
ProjectId: types.StringValue("project1"),
InstanceId: types.StringValue("instance1"),
},
expectedName: "alert-group-name",
expectedID: "project1,instance1,alert-group-name",
expectErr: true,
},
{
name: "Name Missing",
alertGroup: &observability.AlertGroup{
Interval: utils.Ptr("5m"),
},
model: &Model{
Name: types.StringValue("model-name"),
InstanceId: types.StringValue("instance1"),
},
expectErr: true,
},
{
name: "Complete Model and AlertGroup",
alertGroup: &observability.AlertGroup{
Name: utils.Ptr("alert-group-name"),
Interval: utils.Ptr("10m"),
},
model: &Model{
Name: types.StringValue("alert-group-name"),
ProjectId: types.StringValue("project1"),
InstanceId: types.StringValue("instance1"),
Id: types.StringValue("project1,instance1,alert-group-name"),
Interval: types.StringValue("10m"),
},
expectedName: "alert-group-name",
expectedID: "project1,instance1,alert-group-name",
expectErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
err := mapFields(ctx, tt.alertGroup, tt.model)
if (err != nil) != tt.expectErr {
t.Fatalf("expected error: %v, got: %v", tt.expectErr, err)
}
if !tt.expectErr {
if diff := cmp.Diff(tt.model.Name.ValueString(), tt.expectedName); diff != "" {
t.Errorf("unexpected name (-got +want):\n%s", diff)
}
if diff := cmp.Diff(tt.model.Id.ValueString(), tt.expectedID); diff != "" {
t.Errorf("unexpected ID (-got +want):\n%s", diff)
}
}
})
}
}
func TestMapRules(t *testing.T) {
tests := []struct {
name string
alertGroup *observability.AlertGroup
model *Model
expectErr bool
}{
{
name: "Empty Rules",
alertGroup: &observability.AlertGroup{
Rules: &[]observability.AlertRuleRecord{},
},
model: &Model{},
expectErr: false,
},
{
name: "Single Complete Rule",
alertGroup: &observability.AlertGroup{
Rules: &[]observability.AlertRuleRecord{
{
Alert: utils.Ptr("HighCPUUsage"),
Expr: utils.Ptr("rate(cpu_usage[5m]) > 0.9"),
For: utils.Ptr("2m"),
Labels: &map[string]string{"severity": "critical"},
Annotations: &map[string]string{"summary": "CPU usage high"},
Record: utils.Ptr("record1"),
},
},
},
model: &Model{},
expectErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
err := mapRules(ctx, tt.alertGroup, tt.model)
if (err != nil) != tt.expectErr {
t.Fatalf("expected error: %v, got: %v", tt.expectErr, err != nil)
}
})
}
}