diff --git a/tests/.env b/tests/.env index 55ca850c412..67842c99c54 100644 --- a/tests/.env +++ b/tests/.env @@ -30,3 +30,7 @@ OPENSTACK_AUTH_URL= OPENSTACK_PASSWORD= OPENSTACK_PROJECT_ID= OPENSTACK_USER_ID= +NEWRELIC_REGION= +NEWRELIC_ACCOUNT_ID= +NEWRELIC_LICENSE= +NEWRELIC_API_KEY= diff --git a/tests/scalers/new-relic.test.ts b/tests/scalers/new-relic.test.ts index 9008a34352a..eef0d61a7d4 100644 --- a/tests/scalers/new-relic.test.ts +++ b/tests/scalers/new-relic.test.ts @@ -183,103 +183,5 @@ spec: activeDeadlineSeconds: 600 backoffLimit: 2` -const deployYaml = `apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: test-app - name: test-app -spec: - replicas: 1 - selector: - matchLabels: - app: test-app - template: - metadata: - labels: - app: test-app - type: keda-testing - spec: - containers: - - name: prom-test-app - image: tbickford/simple-web-app-prometheus:a13ade9 - imagePullPolicy: IfNotPresent ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app: keda-test-app - name: keda-test-app -spec: - replicas: 0 - selector: - matchLabels: - app: keda-test-app - template: - metadata: - labels: - app: keda-test-app - type: keda-testing - spec: - containers: - - name: prom-test-app - image: tbickford/simple-web-app-prometheus:a13ade9 - imagePullPolicy: IfNotPresent ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app: test-app - annotations: - prometheus.io/scrape: "true" - name: test-app -spec: - ports: - - name: http - port: 80 - protocol: TCP - targetPort: 8080 - selector: - type: keda-testing ---- -apiVersion: keda.sh/v1alpha1 -kind: TriggerAuthentication -metadata: - name: newrelic-trigger -spec: - secretTargetRef: - - parameter: queryKey - name: newrelic-secret - key: newRelicApiKey ---- -apiVersion: v1 -kind: Secret -metadata: - name: newrelic-secret -type: Opaque -data: - newRelicApiKey: {{NEWRELIC_API_KEY}} ---- -apiVersion: keda.sh/v1alpha1 -kind: ScaledObject -metadata: - name: new-relic-scaledobject -spec: - scaleTargetRef: - name: keda-test-app - minReplicaCount: 0 - maxReplicaCount: 3 - pollingInterval: 5 - cooldownPeriod: 10 - triggers: - - type: new-relic - metadata: - account: '{{NEWRELIC_ACCOUNT_ID}}' - region: '{{NEWRELIC_REGION}}' - threshold: '10' - nrql: SELECT average(\`http_requests_total\`) FROM Metric where serviceName='test-app' and namespaceName='new-relic-test' since 60 seconds ago - authenticationRef: - name: newrelic-trigger +const deployYaml = ` ` diff --git a/tests/scalers_go/new_relic/new_relic_test.go b/tests/scalers_go/new_relic/new_relic_test.go new file mode 100644 index 00000000000..18c7d1479f7 --- /dev/null +++ b/tests/scalers_go/new_relic/new_relic_test.go @@ -0,0 +1,270 @@ +//go:build e2e +// +build e2e + +package new_relic_test + +import ( + "encoding/base64" + "fmt" + "os" + "testing" + "time" + + "github.com/joho/godotenv" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "k8s.io/client-go/kubernetes" + + . "github.com/kedacore/keda/v2/tests/helper" +) + +// Load environment variables from .env file +var _ = godotenv.Load("../../.env") +var now = time.Now() + +const ( + testName = "new-relic-test" +) + +var ( + testNamespace = fmt.Sprintf("%s-ns", testName) + deploymentName = fmt.Sprintf("%s-deployment", testName) + serviceName = fmt.Sprintf("%s-service-%v", testName, now.Unix()) + monitoredDeploymentName = fmt.Sprintf("%s-monitored-deployment", testName) + scaledObjectName = fmt.Sprintf("%s-so", testName) + secretName = fmt.Sprintf("%s-secret", testName) + triggerAuthName = fmt.Sprintf("%s-ta", testName) + newRelicApiKey = os.Getenv("NEWRELIC_API_KEY") + newRelicLicenseKey = os.Getenv("NEWRELIC_LICENSE") + newRelicRegion = os.Getenv("NEWRELIC_REGION") + newRelicAccountId = os.Getenv("NEWRELIC_ACCOUNT_ID") + kuberneteClusterName = "keda-new-relic-cluster" + newRelicHelmRepoUrl = "https://helm-charts.newrelic.com" + deploymentReplicas = 1 + minReplicaCount = 1 + maxReplicaCount = 3 +) + +type templateData struct { + TestNamespace string + DeploymentName string + ServiceName string + ScaledObjectName string + TriggerAuthName string + SecretName string + NewRelicApiKey string + DeploymentReplicas string + NewRelicRegion string + NewRelicAccountID string + KuberneteClusterName string + MinReplicaCount string + MaxReplicaCount string +} +type templateValues map[string]string + +const ( + secretTemplate = `apiVersion: v1 +kind: Secret +metadata: + name: {{.SecretName}} + namespace: {{.TestNamespace}} +data: + newRelicApiKey: {{.NewRelicApiKey}} +` + + triggerAuthenticationTemplate = `apiVersion: keda.sh/v1alpha1 +kind: TriggerAuthentication +metadata: + name: {{.TriggerAuthName}} + namespace: {{.TestNamespace}} +spec: + secretTargetRef: + - parameter: queryKey # Required. + name: {{.SecretName}} # Required. + key: newRelicApiKey # Required. +` + + deploymentTemplate = `apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{.DeploymentName}} + namespace: {{.TestNamespace}} + labels: + app: {{.DeploymentName}} +spec: + replicas: {{.DeploymentReplicas}} + selector: + matchLabels: + app: {{.DeploymentName}} + template: + metadata: + labels: + app: {{.DeploymentName}} + spec: + containers: + - name: prom-test-app + image: tbickford/simple-web-app-prometheus:a13ade9 + imagePullPolicy: IfNotPresent +` + + serviceTemplate = `apiVersion: v1 +kind: Service +metadata: + labels: + name: {{.ServiceName}} + namespace: {{.TestNamespace}} + annotations: + prometheus.io/scrape: "true" + name: {{.ServiceName}} +spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 8080 + selector: + app: {{.DeploymentName}} + ` + + scaledObjectTemplate = `apiVersion: keda.sh/v1alpha1 +kind: ScaledObject +metadata: + name: {{.ScaledObjectName}} + namespace: {{.TestNamespace}} + labels: + app: {{.DeploymentName}} +spec: + scaleTargetRef: + name: {{.DeploymentName}} + minReplicaCount: {{.MinReplicaCount}} + maxReplicaCount: {{.MaxReplicaCount}} + pollingInterval: 1 + cooldownPeriod: 1 + advanced: + horizontalPodAutoscalerConfig: + behavior: + scaleDown: + stabilizationWindowSeconds: 10 + triggers: + - type: new-relic + metadata: + account: "{{.NewRelicAccountID}}" + region: {{.NewRelicRegion}} + threshold: "2" + nrql: SELECT rate(sum(http_requests_total), 1 SECONDS) FROM Metric where serviceName='{{.ServiceName}}' and namespaceName='{{.TestNamespace}}' since 120 seconds ago + authenticationRef: + name: {{.TriggerAuthName}} +` + + lightLoadTemplate = `apiVersion: v1 +kind: Pod +metadata: + name: fake-light-traffic + namespace: {{.TestNamespace}} +spec: + containers: + - image: busybox + name: test + command: ["/bin/sh"] + args: ["-c", "while true; do wget -O /dev/null -o /dev/null http://{{.ServiceName}}/; sleep 0.5; done"]` + + heavyLoadTemplate = `apiVersion: v1 +kind: Pod +metadata: + name: fake-heavy-traffic + namespace: {{.TestNamespace}} +spec: + containers: + - image: busybox + name: test + command: ["/bin/sh"] + args: ["-c", "while true; do wget -O /dev/null -o /dev/null http://{{.ServiceName}}/; sleep 0.1; done"]` +) + +func TestNewRelicScaler(t *testing.T) { + // setup + t.Log("--- setting up ---") + require.NotEmpty(t, newRelicApiKey, "NEWRELIC_API_KEY env variable is required for new relic tests") + require.NotEmpty(t, newRelicLicenseKey, "NEWRELIC_LICENSE env variable is required for new relic tests") + require.NotEmpty(t, newRelicAccountId, "NEWRELIC_ACCOUNT_ID env variable is required for new relic tests") + require.NotEmpty(t, newRelicRegion, "NEWRELIC_REGION env variable is required for new relic tests") + + // Create kubernetes resources + kc := GetKubernetesClient(t) + data, templates := getTemplateData() + CreateKubernetesResources(t, kc, testNamespace, data, templates) + + installNewRelic(t) + + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, minReplicaCount, 60, 1), + "replica count should be %s after a minute", minReplicaCount) + + // test scaling + testActivation(t, kc, data) + testScaleUp(t, kc, data) + testScaleDown(t, kc, data) + + // cleanup + DeleteKubernetesResources(t, kc, testNamespace, data, templates) +} + +func testActivation(t *testing.T, kc *kubernetes.Clientset, data templateData) { + t.Log("--- testing activation ---") + KubectlApplyWithTemplate(t, data, "lightLoadTemplate", lightLoadTemplate) + + AssertReplicaCountNotChangeDuringTimePeriod(t, kc, deploymentName, testNamespace, minReplicaCount, 60) +} + +func testScaleUp(t *testing.T, kc *kubernetes.Clientset, data templateData) { + t.Log("--- testing scale up ---") + KubectlApplyWithTemplate(t, data, "heavyLoadTemplate", heavyLoadTemplate) + + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, maxReplicaCount, 60, 3), + "replica count should be %d after 3 minutes", maxReplicaCount) +} + +func testScaleDown(t *testing.T, kc *kubernetes.Clientset, data templateData) { + t.Log("--- testing scale down ---") + KubectlDeleteWithTemplate(t, data, "lightLoadTemplate", lightLoadTemplate) + KubectlDeleteWithTemplate(t, data, "heavyLoadTemplate", heavyLoadTemplate) + assert.True(t, WaitForDeploymentReplicaReadyCount(t, kc, deploymentName, testNamespace, minReplicaCount, 60, 3), + "replica count should be %d after 3 minutes", minReplicaCount) +} + +func installNewRelic(t *testing.T) { + _, err := ExecuteCommand(fmt.Sprintf("helm repo add new-relic %s", newRelicHelmRepoUrl)) + assert.NoErrorf(t, err, "cannot execute command - %s", err) + _, err = ExecuteCommand("helm repo update") + assert.NoErrorf(t, err, "cannot execute command - %s", err) + + cmd := fmt.Sprintf(`helm upgrade --install --set global.cluster=%s --set prometheus.enabled=true --set ksm.enabled=true --set global.lowDataMode=true --set global.licenseKey=%s --timeout 600s --set logging.enabled=false --set ksm.enabled=true --set logging.enabled=true --namespace %s ri-keda new-relic/nri-bundle`, + kuberneteClusterName, + newRelicLicenseKey, + testNamespace) + + _, err = ExecuteCommand(cmd) + assert.NoErrorf(t, err, "cannot execute command - %s", err) +} + +func getTemplateData() (templateData, templateValues) { + return templateData{ + TestNamespace: testNamespace, + DeploymentName: deploymentName, + ServiceName: serviceName, + TriggerAuthName: triggerAuthName, + ScaledObjectName: scaledObjectName, + SecretName: secretName, + NewRelicRegion: newRelicRegion, + KuberneteClusterName: kuberneteClusterName, + MinReplicaCount: fmt.Sprintf("%v", minReplicaCount), + MaxReplicaCount: fmt.Sprintf("%v", maxReplicaCount), + DeploymentReplicas: fmt.Sprintf("%v", deploymentReplicas), + NewRelicAccountID: newRelicAccountId, + NewRelicApiKey: base64.StdEncoding.EncodeToString([]byte(newRelicApiKey)), + }, templateValues{ + "secretTemplate": secretTemplate, + "triggerAuthenticationTemplate": triggerAuthenticationTemplate, + "serviceTemplate": serviceTemplate, + "deploymentTemplate": deploymentTemplate, + "scaledObjectTemplate": scaledObjectTemplate} +}