Skip to content

Commit

Permalink
refactor and tests for notifification recipient read state
Browse files Browse the repository at this point in the history
  • Loading branch information
jharley committed Feb 16, 2024
1 parent 24e9f86 commit f4c841b
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 4 deletions.
2 changes: 1 addition & 1 deletion internal/provider/burn_alert_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ func (r *burnAlertResource) Read(ctx context.Context, req resource.ReadRequest,
state.ID = types.StringValue(burnAlert.ID)
state.AlertType = types.StringValue(string(burnAlert.AlertType))
state.SLOID = types.StringValue(burnAlert.SLO.ID)
state.Recipients = reconcileNotificationRecipientState(burnAlert.Recipients, state.Recipients)
state.Recipients = reconcileReadNotificationRecipientState(burnAlert.Recipients, state.Recipients)

// Process any attributes that could be nil and add them to the state values
if burnAlert.ExhaustionMinutes != nil {
Expand Down
5 changes: 3 additions & 2 deletions internal/provider/notification_recipients.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,15 @@ func notificationRecipientSchema(allowedTypes []client.RecipientType) schema.Set
}
}

func reconcileNotificationRecipientState(remote []client.NotificationRecipient, state []models.NotificationRecipientModel) []models.NotificationRecipientModel {
func reconcileReadNotificationRecipientState(remote []client.NotificationRecipient, state []models.NotificationRecipientModel) []models.NotificationRecipientModel {
if state == nil {
// if we don't have any state, we can't reconcile anything so just return the remote recipients
return flattenNotificationRecipients(remote)
}

recipients := make([]models.NotificationRecipientModel, len(remote))
// match the remote recipients to those in the state sorting out type+target vs ID
// match the remote recipients to those in the state
// in an effort to preserve the id vs type+target distinction
for i, r := range remote {
idx := slices.IndexFunc(state, func(s models.NotificationRecipientModel) bool {
if !s.ID.IsNull() {
Expand Down
140 changes: 140 additions & 0 deletions internal/provider/notification_recipients_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package provider

import (
"testing"

"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stretchr/testify/assert"

"github.com/honeycombio/terraform-provider-honeycombio/client"
"github.com/honeycombio/terraform-provider-honeycombio/internal/models"
)

func Test_reconcileReadNotificationRecipientState(t *testing.T) {
type args struct {
remote []client.NotificationRecipient
state []models.NotificationRecipientModel
}
tests := []struct {
name string
args args
want []models.NotificationRecipientModel
}{
{
name: "both empty",
args: args{},
want: []models.NotificationRecipientModel{},
},
{
name: "empty state",
args: args{
remote: []client.NotificationRecipient{
{ID: "abcd12345", Type: client.RecipientTypeEmail, Target: "[email protected]"},
},
state: []models.NotificationRecipientModel{},
},
want: []models.NotificationRecipientModel{
{ID: types.StringValue("abcd12345"), Type: types.StringValue("email"), Target: types.StringValue("[email protected]")},
},
},
{
name: "empty remote",
args: args{
remote: []client.NotificationRecipient{},
state: []models.NotificationRecipientModel{
{ID: types.StringValue("abcd12345"), Type: types.StringValue("email"), Target: types.StringValue("[email protected]")},
},
},
want: []models.NotificationRecipientModel{},
},
{
name: "remote and state reconciled",
args: args{
remote: []client.NotificationRecipient{
{ID: "abcd12345", Type: client.RecipientTypeEmail, Target: "[email protected]"},
{ID: "efgh67890", Type: client.RecipientTypeSlack, Target: "#test-channel"},
},
state: []models.NotificationRecipientModel{
{ID: types.StringValue("abcd12345")}, // defined by ID
{Type: types.StringValue("slack"), Target: types.StringValue("#test-channel")}, // defined by type+target
},
},
want: []models.NotificationRecipientModel{
{ID: types.StringValue("abcd12345")},
{Type: types.StringValue("slack"), Target: types.StringValue("#test-channel")},
},
},
{
name: "remote has additional recipients",
args: args{
remote: []client.NotificationRecipient{
{ID: "abcd12345", Type: client.RecipientTypeEmail, Target: "[email protected]"},
{ID: "efgh67890", Type: client.RecipientTypeSlack, Target: "#test-channel"},
{ID: "qrsty3847", Type: client.RecipientTypeSlack, Target: "#test-alerts"},
{
ID: "ijkl13579",
Type: client.RecipientTypePagerDuty,
Target: "test-pagerduty",
Details: &client.NotificationRecipientDetails{
PDSeverity: client.PDSeverityWARNING,
}},
},
state: []models.NotificationRecipientModel{
{ID: types.StringValue("abcd12345")}, // defined by ID
{Type: types.StringValue("slack"), Target: types.StringValue("#test-channel")}, // defined by type+target
},
},
want: []models.NotificationRecipientModel{
{ID: types.StringValue("abcd12345")},
{Type: types.StringValue("slack"), Target: types.StringValue("#test-channel")},
{ID: types.StringValue("qrsty3847"), Type: types.StringValue("slack"), Target: types.StringValue("#test-alerts")},
{
ID: types.StringValue("ijkl13579"),
Type: types.StringValue("pagerduty"),
Target: types.StringValue("test-pagerduty"),
Details: []models.NotificationRecipientDetailsModel{
{PDSeverity: types.StringValue("warning")},
},
},
},
},
{
name: "state has additional recipients",
args: args{
remote: []client.NotificationRecipient{
{ID: "efgh67890", Type: client.RecipientTypeSlack, Target: "#test-foo"},
},
state: []models.NotificationRecipientModel{
{ID: types.StringValue("abcd12345")},
{Type: types.StringValue("slack"), Target: types.StringValue("#test-foo")},
{ID: types.StringValue("ijkl13579"), Details: []models.NotificationRecipientDetailsModel{{PDSeverity: types.StringValue("warning")}}},
},
},
want: []models.NotificationRecipientModel{
{Type: types.StringValue("slack"), Target: types.StringValue("#test-foo")},
},
},
{
name: "state has totally unmatched recipients",
args: args{
remote: []client.NotificationRecipient{
{ID: "efgh67890", Type: client.RecipientTypeSlack, Target: "#test-foo"},
},
state: []models.NotificationRecipientModel{
{ID: types.StringValue("abcd12345")},
{Type: types.StringValue("slack"), Target: types.StringValue("#test-channel")},
{ID: types.StringValue("ijkl13579"), Details: []models.NotificationRecipientDetailsModel{{PDSeverity: types.StringValue("warning")}}},
},
},
want: []models.NotificationRecipientModel{
{ID: types.StringValue("efgh67890"), Type: types.StringValue("slack"), Target: types.StringValue("#test-foo")},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, reconcileReadNotificationRecipientState(tt.args.remote, tt.args.state))
})
}
}
2 changes: 1 addition & 1 deletion internal/provider/trigger_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ func (r *triggerResource) Read(ctx context.Context, req resource.ReadRequest, re
state.Threshold = flattenTriggerThreshold(trigger.Threshold)
state.Frequency = types.Int64Value(int64(trigger.Frequency))
state.EvaluationSchedule = flattenTriggerEvaluationSchedule(trigger)
state.Recipients = reconcileNotificationRecipientState(trigger.Recipients, state.Recipients)
state.Recipients = reconcileReadNotificationRecipientState(trigger.Recipients, state.Recipients)

resp.Diagnostics.Append(resp.State.Set(ctx, state)...)
}
Expand Down

0 comments on commit f4c841b

Please sign in to comment.