From cac32ce0ac5aa936504f461bd9d30d1010e12c80 Mon Sep 17 00:00:00 2001 From: leonnicolas Date: Fri, 6 Dec 2024 22:48:58 +0100 Subject: [PATCH] Add e2e test Add a test that deploys the example manifest to a kind cluster and checks if any of the configured labels are attachted to the k8s node. --- .dockerignore | 2 - .github/workflows/build.yaml | 12 ----- .github/workflows/push.yaml | 14 +++--- .github/workflows/test.yaml | 13 +++++ Dockerfile | 4 +- example.yaml | 5 +- go.mod | 6 +++ go.sum | 8 ++++ main_test.go | 93 ++++++++++++++++++++++++++++++++++++ 9 files changed, 132 insertions(+), 25 deletions(-) delete mode 100644 .dockerignore delete mode 100644 .github/workflows/build.yaml create mode 100644 .github/workflows/test.yaml create mode 100644 main_test.go diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index b79324f..0000000 --- a/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -.git/ -.github/ diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml deleted file mode 100644 index abfcdaa..0000000 --- a/.github/workflows/build.yaml +++ /dev/null @@ -1,12 +0,0 @@ -name: build - -on: - pull_request: - -jobs: - main: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - run: docker build -t test . diff --git a/.github/workflows/push.yaml b/.github/workflows/push.yaml index dac66d0..3e078ee 100644 --- a/.github/workflows/push.yaml +++ b/.github/workflows/push.yaml @@ -10,26 +10,26 @@ jobs: main: runs-on: ubuntu-latest steps: - - + - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - id: sha run: echo "::set-output name=sha::$(git describe --always --tags --dirty)" - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_PW }} - name: Login to GitHub Container Registry - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -37,7 +37,7 @@ jobs: - name: Build and push id: docker_build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v6 with: push: true platforms: linux/arm64, linux/arm, linux/amd64 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..1126b3a --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,13 @@ +name: test + +on: + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - run: docker build -t "nudle:e2e" . + - run: go test . diff --git a/Dockerfile b/Dockerfile index 139f05a..cdeb20e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.23-bookworm as build +FROM golang:1.23-bookworm AS build RUN apt-get update && apt-get install libusb-1.0-0-dev -y @@ -7,7 +7,7 @@ WORKDIR /nudl COPY go.mod go.sum /nudl/ RUN go mod download -COPY . /nudl +COPY main.go /nudl RUN ls -la WORKDIR /nudl RUN go build -o nudl diff --git a/example.yaml b/example.yaml index 6b23763..f61b095 100644 --- a/example.yaml +++ b/example.yaml @@ -32,7 +32,7 @@ subjects: --- kind: DaemonSet apiVersion: apps/v1 -metadata: +metadata: name: nudl labels: app.kubernetes.io/name: nudl @@ -49,7 +49,8 @@ spec: containers: - name: nudl image: ghcr.io/leonnicolas/nudl - args: + imagePullPolicy: IfNotPresent + args: - --hostname=$(NODE_NAME) - --no-contain=usb,hub env: diff --git a/go.mod b/go.mod index 24181c0..8ade30f 100644 --- a/go.mod +++ b/go.mod @@ -3,15 +3,20 @@ module github.com/leonnicolas/nudl go 1.23.2 require ( + github.com/efficientgo/core v1.0.0-rc.0 + github.com/efficientgo/e2e v0.14.1-0.20240418111536-97db25a0c6c0 github.com/go-kit/log v0.2.1 github.com/google/gousb v1.1.3 github.com/prometheus/client_golang v1.19.0 github.com/spf13/pflag v1.0.5 + github.com/stretchr/testify v1.8.4 k8s.io/api v0.30.0 k8s.io/apimachinery v0.30.0 k8s.io/client-go v0.30.0 ) +replace github.com/efficientgo/e2e v0.14.1-0.20240418111536-97db25a0c6c0 => github.com/leonnicolas/e2e v0.14.1-0.20241206212748-bd1e26e8cb50 + require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect @@ -34,6 +39,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.48.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect diff --git a/go.sum b/go.sum index f974cec..a86dfb3 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/efficientgo/core v1.0.0-rc.0 h1:jJoA0N+C4/knWYVZ6GrdHOtDyrg8Y/TR4vFpTaqTsqs= +github.com/efficientgo/core v1.0.0-rc.0/go.mod h1:kQa0V74HNYMfuJH6jiPiwNdpWXl4xd/K4tzlrcvYDQI= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= @@ -45,6 +47,8 @@ github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -56,6 +60,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leonnicolas/e2e v0.14.1-0.20241206212748-bd1e26e8cb50 h1:F9prGfkP2ObQLelUQMpTNPO0ChjBrxZedjhBVv5vWJI= +github.com/leonnicolas/e2e v0.14.1-0.20241206212748-bd1e26e8cb50/go.mod h1:plsKU0YHE9uX+7utvr7SiDtVBSHJyEfHRO4UnUgDmts= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -65,6 +71,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= github.com/onsi/gomega v1.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE= diff --git a/main_test.go b/main_test.go new file mode 100644 index 0000000..6b1b965 --- /dev/null +++ b/main_test.go @@ -0,0 +1,93 @@ +package main + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "os/exec" + "strings" + "testing" + "time" + + "github.com/efficientgo/core/backoff" + "github.com/efficientgo/e2e" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const imageName = "nudl:e2e" + +func kubectl(e *e2e.KindEnvironment, args ...string) *exec.Cmd { + return exec.Command("kubectl", append([]string{"--kubeconfig", fmt.Sprintf("%s/kubeconfig", e.SharedDir())}, args...)...) +} + +func kubectlRun(t *testing.T, e *e2e.KindEnvironment, args ...string) { + cmd := kubectl(e, args...) + w := &bytes.Buffer{} + cmd.Stderr = w + cmd.Stdout = w + + require.NoError(t, cmd.Run(), w.String()) +} + +func TestMain(t *testing.T) { + e, err := e2e.NewKindEnvironment() + require.NoError(t, err) + t.Cleanup(e.Close) + + runnableBuilder := e.Runnable(strings.ToLower(t.Name())) + runnable := runnableBuilder.Init(e2e.StartOptions{ + Image: imageName, + }) + _ = runnable.Start() // lazy hack to get image loaded into the cluster + + kubectlRun(t, e, "apply", "-f", "example.yaml") + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + t.Cleanup(cancel) + bo := backoff.New(ctx, backoff.Config{}) + for { + var err error + if bo.Wait(); bo.Ongoing() { + cmd := kubectl(e, "wait", "pod", "--for", "condition=Ready", "--selector", "app.kubernetes.io/name=nudl") + if err = cmd.Run(); err == nil { + break + } + } else { + require.NoError(t, err, "timeout waiting for daemonset") + break + } + } + + { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + t.Cleanup(cancel) + bo := backoff.New(ctx, backoff.Config{}) + found := false + for { + if bo.Wait(); bo.Ongoing() { + cmd := exec.Command("kubectl", "--kubeconfig", fmt.Sprintf("%s/kubeconfig", e.SharedDir()), "get", "nodes", fmt.Sprintf("%s-control-plane", e.Name()), "-o", "jsonpath={.metadata.labels}") + w := &bytes.Buffer{} + cmd.Stderr = w + cmd.Stdout = w + require.NoError(t, cmd.Run(), w.String()) + labels := map[string]string{} + t.Logf("buffer %s\n", w.String()) + + require.NoError(t, json.NewDecoder(w).Decode(&labels), w.String()) + + for key, value := range labels { + if strings.HasPrefix(key, "nudl.squat.ai") { + found = true + t.Logf("found label %s=%s\n", key, value) + break + } + } + } else { + break + } + } + assert.True(t, found, "no label found") + require.NoError(t, err, "timeout waiting for daemonset") + } +}