Skip to content

Commit

Permalink
test: added e2e test for discovery
Browse files Browse the repository at this point in the history
  • Loading branch information
ReuDa committed Jul 6, 2023
1 parent 3d6b695 commit 9bd7aab
Show file tree
Hide file tree
Showing 15 changed files with 487 additions and 24 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/extension-datadog
extension-datadog.iml
/coverage.out
/extension-datadog.run.xml
/e2e/e2e-coverage-docker.out
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ FROM golang:1.20-alpine AS build
ARG NAME
ARG VERSION
ARG REVISION
ARG ADDITIONAL_BUILD_PARAMS

WORKDIR /app

Expand All @@ -23,7 +24,8 @@ RUN go build \
-X 'github.com/steadybit/extension-kit/extbuild.ExtensionName=${NAME}' \
-X 'github.com/steadybit/extension-kit/extbuild.Version=${VERSION}' \
-X 'github.com/steadybit/extension-kit/extbuild.Revision=${REVISION}'" \
-o ./extension
-o ./extension \
${ADDITIONAL_BUILD_PARAMS}

##
## Runtime
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,4 @@ run: tidy build
## container: build the container image
.PHONY: container
container:
docker build -t extension-datadog:latest .
docker build --build-arg ADDITIONAL_BUILD_PARAMS="-cover" -t extension-datadog:latest .
2 changes: 1 addition & 1 deletion charts/steadybit-extension-datadog/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
apiVersion: v2
name: steadybit-extension-datadog
description: Steadybit Kubernetes extension Helm chart for Datadog.
version: 1.4.8
version: 1.4.9
appVersion: latest
home: https://www.steadybit.com/
icon: https://steadybit-website-assets.s3.amazonaws.com/logo-symbol-transparent.png
Expand Down
8 changes: 8 additions & 0 deletions charts/steadybit-extension-datadog/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ spec:
secretKeyRef:
name: {{ include "datadog.secret.name" . }}
key: site-url
{{ if .Values.testing.scheme -}}
- name: STEADYBIT_EXTENSION_TESTING_SCHEME
value: {{ .Values.testing.scheme }}
{{ end }}
{{ if .Values.testing.host -}}
- name: STEADYBIT_EXTENSION_TESTING_HOST
value: {{ .Values.testing.host }}
{{ end }}
{{- with .Values.extraEnv }}
{{- toYaml . | nindent 12 }}
{{- end }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,81 @@ manifest should match snapshot with extra env vars:
runAsUser: 10000
volumeMounts: null
volumes: null
manifest should match snapshot with mock server:
1: |
apiVersion: apps/v1
kind: Deployment
metadata:
labels: null
name: RELEASE-NAME-steadybit-extension-datadog
namespace: NAMESPACE
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: steadybit-extension-datadog
template:
metadata:
labels:
app.kubernetes.io/name: steadybit-extension-datadog
spec:
containers:
- env:
- name: STEADYBIT_LOG_LEVEL
value: INFO
- name: STEADYBIT_LOG_FORMAT
value: text
- name: STEADYBIT_EXTENSION_API_KEY
valueFrom:
secretKeyRef:
key: api-key
name: steadybit-extension-datadog
- name: STEADYBIT_EXTENSION_APPLICATION_KEY
valueFrom:
secretKeyRef:
key: application-key
name: steadybit-extension-datadog
- name: STEADYBIT_EXTENSION_SITE_PARAMETER
valueFrom:
secretKeyRef:
key: site-parameter
name: steadybit-extension-datadog
- name: STEADYBIT_EXTENSION_SITE_URL
valueFrom:
secretKeyRef:
key: site-url
name: steadybit-extension-datadog
- name: STEADYBIT_EXTENSION_TESTING_SCHEME
value: http
- name: STEADYBIT_EXTENSION_TESTING_HOST
value: host.minikube.internal:8080
image: ghcr.io/steadybit/extension-datadog:latest
imagePullPolicy: Always
livenessProbe:
httpGet:
path: /health/liveness
port: 8091
name: extension
ports:
- containerPort: 8090
readinessProbe:
httpGet:
path: /health/readiness
port: 8091
resources:
limits:
cpu: 200m
memory: 128Mi
requests:
cpu: 50m
memory: 64Mi
securityContext:
readOnlyRootFilesystem: true
runAsGroup: 10000
runAsNonRoot: true
runAsUser: 10000
volumeMounts: null
volumes: null
manifest should match snapshot with mutual TLS:
1: |
apiVersion: apps/v1
Expand Down
7 changes: 7 additions & 0 deletions charts/steadybit-extension-datadog/tests/deployment_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,10 @@ tests:
name: env-secrets
asserts:
- matchSnapshot: {}
- it: manifest should match snapshot with mock server
set:
testing:
scheme: http
host: host.minikube.internal:8080
asserts:
- matchSnapshot: {}
6 changes: 6 additions & 0 deletions charts/steadybit-extension-datadog/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ datadog:
# datadog.existingSecret -- If defined, will skip secret creation and instead assume that the referenced secret contains the keys api-key, application-key, site-parameter and site-url.
existingSecret: null

testing:
# testing.scheme: Override the Datadog API scheme. Useful for testing.
scheme: null
# testing.host: Override the Datadog API host. Useful for testing.
host: null

image:
# image.name -- The container image to use for the Steadybit Datadog extension.
name: ghcr.io/steadybit/extension-datadog
Expand Down
36 changes: 18 additions & 18 deletions config/specification.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ type Specification struct {
SiteUrl string `json:"siteUrl" split_words:"true" required:"true"`
ApiKey string `json:"apiKey" split_words:"true" required:"true"`
ApplicationKey string `json:"applicationKey" split_words:"true" required:"true"`
// Only used for testing:
TestingScheme *string `json:"testingScheme" split_words:"true" required:"false"`
TestingHost *string `json:"testingHost" split_words:"true" required:"false"`
}

func (s *Specification) WrapContextWithDatadogContextValues(ctx context.Context) context.Context {
Expand Down Expand Up @@ -43,44 +46,41 @@ func (s *Specification) WrapContextWithDatadogContextValues(ctx context.Context)
return ctx
}

func (s *Specification) ValidateCredentials(ctx context.Context) (datadogV1.AuthenticationValidationResponse, *http.Response, error) {
func (s *Specification) createApiClient() *datadog.APIClient {
configuration := datadog.NewConfiguration()
apiClient := datadog.NewAPIClient(configuration)
api := datadogV1.NewAuthenticationApi(apiClient)
if s.TestingHost != nil && s.TestingScheme != nil {
configuration.Scheme = *s.TestingScheme
configuration.Host = *s.TestingHost
}
return datadog.NewAPIClient(configuration)
}

func (s *Specification) ValidateCredentials(ctx context.Context) (datadogV1.AuthenticationValidationResponse, *http.Response, error) {
api := datadogV1.NewAuthenticationApi(s.createApiClient())
return api.Validate(s.WrapContextWithDatadogContextValues(ctx))
}

func (s *Specification) ListMonitors(ctx context.Context, params datadogV1.ListMonitorsOptionalParameters) ([]datadogV1.Monitor, *http.Response, error) {
configuration := datadog.NewConfiguration()
apiClient := datadog.NewAPIClient(configuration)
api := datadogV1.NewMonitorsApi(apiClient)
api := datadogV1.NewMonitorsApi(s.createApiClient())
return api.ListMonitors(s.WrapContextWithDatadogContextValues(ctx), params)
}

func (s *Specification) GetMonitor(ctx context.Context, monitorId int64, params datadogV1.GetMonitorOptionalParameters) (datadogV1.Monitor, *http.Response, error) {
configuration := datadog.NewConfiguration()
apiClient := datadog.NewAPIClient(configuration)
api := datadogV1.NewMonitorsApi(apiClient)
api := datadogV1.NewMonitorsApi(s.createApiClient())
return api.GetMonitor(s.WrapContextWithDatadogContextValues(ctx), monitorId, params)
}

func (s *Specification) CreateDowntime(ctx context.Context, downtimeBody datadogV1.Downtime) (datadogV1.Downtime, *http.Response, error) {
configuration := datadog.NewConfiguration()
apiClient := datadog.NewAPIClient(configuration)
api := datadogV1.NewDowntimesApi(apiClient)
api := datadogV1.NewDowntimesApi(s.createApiClient())
return api.CreateDowntime(s.WrapContextWithDatadogContextValues(ctx), downtimeBody)
}

func (s *Specification) CancelDowntime(ctx context.Context, downtimeId int64) (*http.Response, error) {
configuration := datadog.NewConfiguration()
apiClient := datadog.NewAPIClient(configuration)
api := datadogV1.NewDowntimesApi(apiClient)
api := datadogV1.NewDowntimesApi(s.createApiClient())
return api.CancelDowntime(s.WrapContextWithDatadogContextValues(ctx), downtimeId)
}

func (s *Specification) SendEvent(ctx context.Context, datadogEventBody datadogV1.EventCreateRequest) (datadogV1.EventCreateResponse, *http.Response, error) {
configuration := datadog.NewConfiguration()
apiClient := datadog.NewAPIClient(configuration)
api := datadogV1.NewEventsApi(apiClient)
api := datadogV1.NewEventsApi(s.createApiClient())
return api.CreateEvent(s.WrapContextWithDatadogContextValues(ctx), datadogEventBody)
}
60 changes: 60 additions & 0 deletions e2e/integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: 2023 Steadybit GmbH

package e2e

import (
"context"
"github.com/steadybit/action-kit/go/action_kit_test/e2e"
"github.com/steadybit/discovery-kit/go/discovery_kit_api"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"strings"
"testing"
"time"
)

func TestWithMinikube(t *testing.T) {
server := createMockDatadogServer()
defer server.Close()
port := strings.SplitAfter(server.URL, ":")[2]

extFactory := e2e.HelmExtensionFactory{
Name: "extension-datadog",
Port: 8090,
ExtraArgs: func(m *e2e.Minikube) []string {
return []string{
"--set", "logging.level=debug",
"--set", "datadog.apiKey=123456-7890",
"--set", "datadog.applicationKey=555-666-777",
"--set", "datadog.siteParameter=datadoghq.eu",
"--set", "datadog.siteUrl=https://app.datadoghq.eu",
"--set", "testing.scheme=http",
"--set", "testing.host=host.minikube.internal:" + port,
}
},
}

mOpts := e2e.DefaultMiniKubeOpts
mOpts.Runtimes = []e2e.Runtime{e2e.RuntimeDocker}

e2e.WithMinikube(t, mOpts, &extFactory, []e2e.WithMinikubeTestCase{
{
Name: "target discovery",
Test: testDiscovery,
},
})
}

func testDiscovery(t *testing.T, m *e2e.Minikube, e *e2e.Extension) {
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()

target, err := e2e.PollForTarget(ctx, e, "com.github.steadybit.extension_datadog.monitor", func(target discovery_kit_api.Target) bool {
return e2e.HasAttribute(target, "datadog.monitor.id", "8080808")
})

require.NoError(t, err)
assert.Equal(t, target.TargetType, "com.github.steadybit.extension_datadog.monitor")
assert.True(t, e2e.HasAttribute(target, "datadog.monitor.name", "[DEV] Monitor Kubernetes Deployments Replica Pods"))
}
82 changes: 82 additions & 0 deletions e2e/mock_datadog_server_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package e2e

import (
"github.com/rs/zerolog/log"
"net/http"
"net/http/httptest"
"strconv"
)

func createMockDatadogServer() *httptest.Server {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Info().Str("path", r.URL.Path).Str("method", r.Method).Str("query", r.URL.RawQuery).Msg("Request received")
if r.URL.Path == "/api/v1/validate" {
w.WriteHeader(http.StatusOK)
w.Write(apiV1Validate())
} else if r.URL.Path == "/api/v1/monitor" {
page, _ := strconv.Atoi(r.URL.Query().Get("page"))
w.WriteHeader(http.StatusOK)
w.Write(apiV1Monitor(page))
} else {
w.WriteHeader(http.StatusBadRequest)
}
}))
return server
}

func apiV1Validate() []byte {
return []byte(`{"valid": true}`)
}

func apiV1Monitor(page int) []byte {
if page == 0 {
return []byte(
`[
{
"id": 8080808,
"org_id": 9090909090,
"type": "query alert",
"name": "[DEV] Monitor Kubernetes Deployments Replica Pods",
"message": "More than one Deployments Replica's pods are down",
"tags": [
"integration:kubernetes",
"env:dev"
],
"query": "min(last_5m):avg:kubernetes_state.deployment.replicas_desired{kube_cluster_name:dev-demo} by {kube_namespace,kube_deployment} - avg:kubernetes_state.deployment.replicas_available{kube_cluster_name:dev-demo} by {kube_namespace,kube_deployment} >= 2",
"options": {
"thresholds": {
"critical": 2.0,
"warning": 1.0
},
"notify_audit": true,
"require_full_window": false,
"notify_no_data": true,
"renotify_interval": 0,
"timeout_h": 0,
"include_tags": true,
"escalation_message": "",
"new_group_delay": 60,
"silenced": {}
},
"multi": true,
"created_at": 1666859636000,
"created": "2022-10-27T08:33:56.272148+00:00",
"modified": "2023-06-20T10:15:46.744422+00:00",
"deleted": null,
"restricted_roles": null,
"priority": null,
"overall_state_modified": "2023-06-21T05:42:33+00:00",
"overall_state": "OK",
"creator": {
"name": "Theo Test",
"handle": "[email protected]",
"email": "[email protected]",
"id": 1010101010
},
"matching_downtimes": []
}
]`)
} else {
return []byte(`[]`)
}
}
Loading

0 comments on commit 9bd7aab

Please sign in to comment.