diff --git a/Makefile b/Makefile index f40e810411794ae47b8c094de20bf5eb66c80f01..6b3651ae9f1579665146b8a73ce1e3c94c9afe43 100644 --- a/Makefile +++ b/Makefile @@ -42,6 +42,9 @@ test: $(JB_BINARY) $(JB_BINARY) install ./test.sh +test-e2e: + go test -timeout 55m -v ./tests/e2e + test-in-docker: ../../hack/jsonnet-docker-image @echo ">> Compiling assets and generating Kubernetes manifests" docker run \ diff --git a/tests/e2e/main_test.go b/tests/e2e/main_test.go new file mode 100644 index 0000000000000000000000000000000000000000..e63730a3df146eb16c30ad7ea9426c198bf4ba14 --- /dev/null +++ b/tests/e2e/main_test.go @@ -0,0 +1,118 @@ +// Copyright 2019 The prometheus-operator Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package e2e + +import ( + "log" + "os" + "testing" + "time" + + "github.com/pkg/errors" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/tools/clientcmd" +) + +var promClient *prometheusClient + +func TestMain(m *testing.M) { + os.Exit(testMain(m)) +} + +// testMain circumvents the issue, that one can not call `defer` in TestMain, as +// `os.Exit` does not honor `defer` statements. For more details see: +// http://blog.englund.nu/golang,/testing/2017/03/12/using-defer-in-testmain.html +func testMain(m *testing.M) int { + kubeConfigPath, ok := os.LookupEnv("KUBECONFIG") + if !ok { + log.Fatal("failed to retrieve KUBECONFIG env var") + } + + config, err := clientcmd.BuildConfigFromFlags("", kubeConfigPath) + if err != nil { + log.Fatal(err) + } + + kubeClient, err := kubernetes.NewForConfig(config) + if err != nil { + log.Fatal(errors.Wrap(err, "creating kubeClient failed")) + } + + promClient = newPrometheusClient(kubeClient) + + return m.Run() +} + +func TestQueryPrometheus(t *testing.T) { + t.Parallel() + queries := []struct { + query string + expectN int + }{ + { + // query: `up{job="node-exporter"} == 1`, + // expectN: 1, + // }, { + // query: `up{job="kubelet"} == 1`, + // expectN: 1, + // }, { + query: `up{job="apiserver"} == 1`, + expectN: 1, + // }, { + // query: `up{job="kube-state-metrics"} == 1`, + // expectN: 1, + }, { + query: `up{job="prometheus-k8s"} == 1`, + expectN: 1, + }, { + query: `up{job="prometheus-operator"} == 1`, + expectN: 1, + }, { + query: `up{job="alertmanager-main"} == 1`, + expectN: 2, + }, + } + + // Wait for pod to respond at queries at all. Then start verifying their results. + err := wait.Poll(5*time.Second, 1*time.Minute, func() (bool, error) { + _, err := promClient.query("up") + return err == nil, nil + }) + if err != nil { + t.Fatal(errors.Wrap(err, "wait for prometheus-k8s")) + } + + err = wait.Poll(5*time.Second, 1*time.Minute, func() (bool, error) { + defer t.Log("---------------------------\n") + + for _, q := range queries { + n, err := promClient.query(q.query) + if err != nil { + return false, err + } + if n < q.expectN { + // Don't return an error as targets may only become visible after a while. + t.Logf("expected at least %d results for %q but got %d", q.expectN, q.query, n) + return false, nil + } + t.Logf("query %q succeeded", q.query) + } + return true, nil + }) + if err != nil { + t.Fatal(err) + } +} diff --git a/tests/e2e/prometheus_client.go b/tests/e2e/prometheus_client.go new file mode 100644 index 0000000000000000000000000000000000000000..b87ce3e5fff8ca7f4b32d392304d2c007eb8703b --- /dev/null +++ b/tests/e2e/prometheus_client.go @@ -0,0 +1,52 @@ +// Copyright 2019 The prometheus-operator Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package e2e + +import ( + "k8s.io/client-go/kubernetes" + + "github.com/Jeffail/gabs" +) + +type prometheusClient struct { + kubeClient kubernetes.Interface +} + +func newPrometheusClient(kubeClient kubernetes.Interface) *prometheusClient { + return &prometheusClient{kubeClient} +} + +// Query makes a request against the Prometheus /api/v1/query endpoint. +func (c *prometheusClient) query(query string) (int, error) { + req := c.kubeClient.CoreV1().RESTClient().Get(). + Namespace("monitoring"). + Resource("pods"). + SubResource("proxy"). + Name("prometheus-k8s-0:9090"). + Suffix("/api/v1/query").Param("query", query) + + b, err := req.DoRaw() + if err != nil { + return 0, err + } + + res, err := gabs.ParseJSON(b) + if err != nil { + return 0, err + } + + n, err := res.ArrayCountP("data.result") + return n, err +} diff --git a/tests/e2e/travis-e2e.sh b/tests/e2e/travis-e2e.sh new file mode 100755 index 0000000000000000000000000000000000000000..45fb974a484bec53906bb972e2a33652ff8d0abc --- /dev/null +++ b/tests/e2e/travis-e2e.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +# exit immediately when a command fails +set -e +# only exit with zero if all commands of the pipeline exit successfully +set -o pipefail +# error on unset variables +set -u +# print each command before executing it +set -x + +SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}") + +"${SCRIPT_DIR}"/../../../../scripts/create-minikube.sh + +# waiting for kube-dns to be ready +JSONPATH='{range .items[*]}{@.metadata.name}:{range @.status.conditions[*]}{@.type}={@.status};{end}{end}'; until kubectl -n kube-system get pods -lk8s-app=kube-dns -o jsonpath="$JSONPATH" 2>&1 | grep -q "Ready=True"; do sleep 1;echo "waiting for kube-dns to be available"; kubectl get pods --all-namespaces; done + +( + cd "${SCRIPT_DIR}"/../.. || exit + kubectl apply -f manifests + KUBECONFIG=~/.kube/config make test-e2e +) + +"${SCRIPT_DIR}"/../../../../scripts/delete-minikube.sh