Skip to content

Commit

Permalink
Add unit test
Browse files Browse the repository at this point in the history
  • Loading branch information
mszostok committed May 15, 2024
1 parent d8441e4 commit be91715
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 46 deletions.
11 changes: 8 additions & 3 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -600,9 +600,14 @@ type Webhook struct {

// PagerDuty describes the PagerDuty sink.
type PagerDuty struct {
Enabled bool `yaml:"enabled"`
IntegrationKey string `yaml:"integrationKey"`
Bindings SinkBindings `yaml:"bindings" validate:"required_if=Enabled true"`
// Enabled indicates if the PagerDuty sink is enabled.
Enabled bool `yaml:"enabled"`
// Bindings are the bindings for the PagerDuty sink.
Bindings SinkBindings `yaml:"bindings" validate:"required_if=Enabled true"`
// IntegrationKey is the PagerDuty integration key generated for Events v2 API.
IntegrationKey string `yaml:"integrationKey" validate:"required_if=Enabled true"`
// V2EventsAPIBasePath is the Events v2 API URL base path. Defaults to https://events.pagerduty.com.
V2EventsAPIBasePath string
}

// CfgWatcher describes configuration for watching the configuration.
Expand Down
18 changes: 11 additions & 7 deletions pkg/sink/pager_duty.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ type EventLink struct {

// NewPagerDuty creates a new PagerDuty instance.
func NewPagerDuty(log logrus.FieldLogger, commGroupIdx int, c config.PagerDuty, clusterName string, reporter AnalyticsReporter) (*PagerDuty, error) {
var opts []pagerduty.ClientOptions
if c.V2EventsAPIBasePath != "" {
opts = append(opts, pagerduty.WithV2EventsAPIEndpoint(c.V2EventsAPIBasePath))
}
notifier := &PagerDuty{
log: log,
reporter: reporter,
Expand All @@ -59,7 +63,7 @@ func NewPagerDuty(log logrus.FieldLogger, commGroupIdx int, c config.PagerDuty,
status: health.StatusUnknown,
failureReason: "",

pagerDutyCli: pagerduty.NewClient(""),
pagerDutyCli: pagerduty.NewClient("", opts...),
}

err := reporter.ReportSinkEnabled(notifier.IntegrationName(), commGroupIdx)
Expand All @@ -82,7 +86,7 @@ func (w *PagerDuty) SendEvent(ctx context.Context, rawData any, sources []string
Timestamp: time.Now(),
}

resp, err := w.postAlertEvent(ctx, jsonPayload)
resp, err := w.postEvent(ctx, jsonPayload)
if err != nil {
w.setFailureReason(health.FailureReasonConnectionError)
return fmt.Errorf("while sending message to PagerDuty: %w", err)
Expand Down Expand Up @@ -120,7 +124,7 @@ func (w *PagerDuty) shouldNotify(sourceBindings []string) bool {
return sliceutil.Intersect(sourceBindings, w.bindings.Sources)
}

func (w *PagerDuty) getEventMeta(in *PagerDutyPayload) eventMetadata {
func (w *PagerDuty) resolveEventMeta(in *PagerDutyPayload) eventMetadata {
out := eventMetadata{
Summary: fmt.Sprintf("Event from %s source", in.Source),
IsAlert: true,
Expand Down Expand Up @@ -148,21 +152,21 @@ func (w *PagerDuty) getEventMeta(in *PagerDutyPayload) eventMetadata {
return out
}

func (w *PagerDuty) postAlertEvent(ctx context.Context, in *PagerDutyPayload) (any, error) {
meta := w.getEventMeta(in)
func (w *PagerDuty) postEvent(ctx context.Context, in *PagerDutyPayload) (any, error) {
meta := w.resolveEventMeta(in)
if meta.IsAlert {
return w.triggerAlert(ctx, in, meta)
}

return w.triggerChange(ctx, in, meta)
}

func (w *PagerDuty) triggerAlert(ctx context.Context, in *PagerDutyPayload, meta eventMetadata) (*pagerduty.V2EventResponse, error) {
return pagerduty.ManageEventWithContext(ctx, pagerduty.V2Event{
return w.pagerDutyCli.ManageEventWithContext(ctx, &pagerduty.V2Event{
// required
RoutingKey: w.integrationKey,
Action: "trigger",

// optional
Client: "Botkube",
ClientURL: "https://app.botkube.io",

Expand Down
129 changes: 93 additions & 36 deletions pkg/sink/pager_duty_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,107 @@ package sink

import (
"context"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/kubeshop/botkube/internal/analytics"
"github.com/kubeshop/botkube/pkg/config"
"github.com/kubeshop/botkube/pkg/loggerx"
)

func Test(t *testing.T) {
duty, err := NewPagerDuty(loggerx.New(config.Logger{
Level: "debug",
Formatter: "text",
}), 0, config.PagerDuty{
Enabled: true,
IntegrationKey: "R03E2UWJRUG6IYKSWEZUUFCPUFRXAK4E",
//AlertAPIURL: "",
//ChangeAPIURL: "",
Bindings: config.SinkBindings{
Sources: []string{"kubernetes-err"},
func TestPagerDuty_SendEvent(t *testing.T) {
const integrationKey = "integration-key"

tests := []struct {
name string
eventType string
statusCode int
expPath string
givenEvent map[string]any
}{
{
name: "alert event",
givenEvent: fixK8sPodErrorAlert(),
expPath: "/v2/enqueue",
},
{
name: "change event",
givenEvent: fixK8sDeployUpdateAlert(),
expPath: "/v2/change/enqueue",
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, tc.expPath, r.URL.Path)

var payload struct {
RoutingKey string `json:"routing_key"`
}
err := json.NewDecoder(r.Body).Decode(&payload)
require.NoError(t, err)
assert.Equal(t, integrationKey, payload.RoutingKey)

w.WriteHeader(http.StatusAccepted)
w.Write([]byte(`{}`))

Check failure on line 53 in pkg/sink/pager_duty_test.go

View workflow job for this annotation

GitHub Actions / golangci-lint

Error return value of `w.Write` is not checked (errcheck)
}))
defer server.Close()

pd, err := NewPagerDuty(loggerx.NewNoop(), 0, config.PagerDuty{
Enabled: true,
IntegrationKey: integrationKey,
V2EventsAPIBasePath: server.URL,
Bindings: config.SinkBindings{
Sources: []string{"kubernetes-err"},
},
}, "labs", analytics.NewNoopReporter())
require.NoError(t, err)

err = pd.SendEvent(context.Background(), tc.givenEvent, []string{"kubernetes-err"})
require.NoError(t, err)
})
}
}

func fixK8sPodErrorAlert() map[string]any {
return map[string]any{
"APIVersion": "v1",
"Kind": "Pod",
"Title": "v1/pods error",
"Name": "webapp",
"Namespace": "dev",
"Resource": "v1/pods",
"Messages": []string{"Back-off restarting failed container webapp in pod webapp_dev(0a405592-2615-4d0c-b399-52ada5a9cc1b)"},
"Type": "error",
"Reason": "BackOff",
"Level": "error",
"Cluster": "labs",
"TimeStamp": "2024-05-14T19:47:24.828568+09:00",
"Count": int32(1),
}
}

func fixK8sDeployUpdateAlert() map[string]any {
return map[string]any{
"API Version": "apps/v1",
"Cluster": "labs",
"Count": 0,
"Kind": "Deployment",
"Level": "info",
"Messages": []string{
"status.availableReplicas:\n\t-: <none>\n\t+: 1\nstatus.readyReplicas:\n\t-: <none>\n\t+: 1\n",
},
}, "labs", analytics.NewNoopReporter())

require.NoError(t, err)

err = duty.SendEvent(context.Background(), map[string]any{
"APIVersion": "v1",
"Kind": "Pod",
"Title": "v1/pods error",
"Name": "webapp",
"Namespace": "dev",
"Messages": []string{"Back-off restarting failed container webapp in pod webapp_dev(0a405592-2615-4d0c-b399-52ada5a9cc1b)"},
"Type": "error",
"Reason": "BackOff",
"Level": "error",
"Cluster": "labs",
"TimeStamp": time.Date(2024, 5, 14, 19, 32, 42, 0, time.FixedZone("+09:00", 9*60*60)),
"Count": int32(1),
"Action": "",
"Skip": false,
"Resource": "v1/pods",
"Recommendations": []string{},
"Warnings": []string{},
}, []string{"kubernetes-err"})
require.NoError(t, err)
"Name": "nginx-deployment",
"Namespace": "botkube",
"Resource": "apps/v1/deployments",
"Title": "apps/v1/deployments updated",
"Type": "update",
"TimeStamp": "2024-05-14T19:47:24.828568+09:00",
}
}

0 comments on commit be91715

Please sign in to comment.