Add tests and run them in CI

This commit is contained in:
Peter 2022-04-13 22:16:58 +02:00
parent 0d70c9b96a
commit 00b7f12d65
Signed by: prskr
GPG key ID: C1DB5D2E8DB512F9
7 changed files with 207 additions and 3 deletions

View file

@ -27,6 +27,15 @@ jobs:
with:
lfs: true
- name: Install gotestsum
run: go install gotest.tools/gotestsum@latest
- name: Create out directory
run: mkdir -p ./out
- name: Run tests
run: gotestsum -- -coverprofile=out/cover.txt -shuffle=on -race -covermode=atomic ./...
- name: golangci-lint
uses: golangci/golangci-lint-action@v3
with:

1
.gitignore vendored
View file

@ -16,3 +16,4 @@
.idea/
dist/
out/

20
.pre-commit-config.yaml Normal file
View file

@ -0,0 +1,20 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/tekwizely/pre-commit-golang
rev: v1.0.0-beta.5
hooks:
- id: go-mod-tidy-repo
args:
- -go=1.18
- id: go-fumpt
args:
- -w
- id: go-imports
args:
- -local=gitlab.com/inetmock/inetmock
- -w
- id: golangci-lint-repo-mod
args:
- --fast
- --fix

1
go.mod
View file

@ -3,6 +3,7 @@ module github.com/baez90/kreaper
go 1.18
require (
github.com/maxatome/go-testdeep v1.11.0
go.uber.org/zap v1.21.0
k8s.io/api v0.23.5
k8s.io/apimachinery v0.23.5

2
go.sum
View file

@ -194,6 +194,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
github.com/maxatome/go-testdeep v1.11.0 h1:Tgh5efyCYyJFGUYiT0qxBSIDeXw0F5zSoatlou685kk=
github.com/maxatome/go-testdeep v1.11.0/go.mod h1:011SgQ6efzZYAen6fDn4BqQ+lUR72ysdyKe7Dyogw70=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=

12
main.go
View file

@ -96,12 +96,18 @@ func prepareFlags() {
"Set target namespace in which kreaper will look for pods - env variable: KREAPER_TARGET_NAMESPACE",
)
var kubeconfigFallback string
if home := homedir.HomeDir(); home != "" {
flag.StringVar(&kubeconfig, "kubeconfig", lookupEnvOr("KUBECONFIG", filepath.Join(home, ".kube", "config"), identity[string]), "(optional) absolute path to the kubeconfig file")
} else {
flag.StringVar(&kubeconfig, "kubeconfig", lookupEnvOr("KUBECONFIG", "", identity[string]), "absolute path to the kubeconfig file")
kubeconfigFallback = filepath.Join(home, ".kube", "config")
}
flag.StringVar(
&kubeconfig,
"kubeconfig",
lookupEnvOr("KUBECONFIG", kubeconfigFallback, identity[string]),
"absolute path to the kubeconfig file",
)
flag.Parse()
}

165
reaper/reaper_test.go Normal file
View file

@ -0,0 +1,165 @@
package reaper_test
import (
"context"
"errors"
"testing"
"time"
"github.com/maxatome/go-testdeep/td"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"github.com/baez90/kreaper/reaper"
)
func TestKreaper_Kill(t *testing.T) {
const defaultNamespace = "default"
t.Parallel()
type fields struct {
initialState corev1.PodList
lifetime time.Duration
target reaper.Target
}
tests := []struct {
name string
fields fields
modifier func(tb testing.TB, k8sClient client.Client)
wantErr error
wantRemaining td.TestDeep
}{
{
name: "Empty initial state",
fields: fields{
lifetime: 10 * time.Second,
target: reaper.Target("app.kubernetes.io/name=ee8dcc4d"),
},
wantRemaining: td.Empty(),
},
{
name: "Single pod to delete",
fields: fields{
target: reaper.Target("app.kubernetes.io/name=ee8dcc4d"),
lifetime: 100 * time.Millisecond,
initialState: corev1.PodList{
Items: []corev1.Pod{
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-asdf234",
Namespace: defaultNamespace,
Labels: map[string]string{
"app.kubernetes.io/name": "ee8dcc4d",
},
},
},
},
},
},
wantRemaining: td.Empty(),
},
{
name: "Single pod to delete - delete preemptively",
fields: fields{
target: reaper.Target("app.kubernetes.io/name=ee8dcc4d"),
lifetime: 100 * time.Millisecond,
initialState: corev1.PodList{
Items: []corev1.Pod{
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-asdf234",
Namespace: defaultNamespace,
Labels: map[string]string{
"app.kubernetes.io/name": "ee8dcc4d",
},
},
},
},
},
},
modifier: func(tb testing.TB, k8sClient client.Client) {
tb.Helper()
td.CmpNoError(tb, k8sClient.DeleteAllOf(context.Background(), new(corev1.Pod)))
},
wantRemaining: td.Empty(),
},
{
name: "Single pod to delete - one should remain",
fields: fields{
target: reaper.Target("app.kubernetes.io/name=ee8dcc4d"),
lifetime: 100 * time.Millisecond,
initialState: corev1.PodList{
Items: []corev1.Pod{
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-asdf234",
Namespace: defaultNamespace,
Labels: map[string]string{
"app.kubernetes.io/name": "ee8dcc4d",
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "demo-lkjklsdf9234",
Namespace: defaultNamespace,
Labels: map[string]string{
"app.kubernetes.io/name": "ef903e61",
},
},
},
},
},
},
wantRemaining: td.Len(1),
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
k8sClient := fake.NewClientBuilder().
WithLists(&tt.fields.initialState).
Build()
k := reaper.Kreaper{
Client: k8sClient,
Lifetime: tt.fields.lifetime,
Target: tt.fields.target,
TargetNamespace: defaultNamespace,
}
ctx, cancel := context.WithCancel(context.Background())
t.Cleanup(cancel)
errs := make(chan error, 1)
go func(ctx context.Context, errs chan<- error) {
defer close(errs)
errs <- k.Kill(ctx)
if err := k.Kill(ctx); !errors.Is(err, tt.wantErr) {
t.Errorf("Kill() error = %v, wantErr %v", err, tt.wantErr)
}
}(ctx, errs)
if tt.modifier != nil {
tt.modifier(t, k8sClient)
}
for err := range errs {
if !errors.Is(err, tt.wantErr) {
t.Errorf("Kill() error = %v, wantErr %v", err, tt.wantErr)
return
}
}
var remainingPods corev1.PodList
if err := k8sClient.List(ctx, &remainingPods); err != nil {
t.Fatalf("Failed to list remaining pods err = %v", err)
}
td.Cmp(t, remainingPods.Items, tt.wantRemaining)
})
}
}