Add tests and run them in CI
This commit is contained in:
parent
0d70c9b96a
commit
00b7f12d65
7 changed files with 207 additions and 3 deletions
9
.github/workflows/go.yml
vendored
9
.github/workflows/go.yml
vendored
|
@ -27,6 +27,15 @@ jobs:
|
||||||
with:
|
with:
|
||||||
lfs: true
|
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
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v3
|
uses: golangci/golangci-lint-action@v3
|
||||||
with:
|
with:
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -16,3 +16,4 @@
|
||||||
|
|
||||||
.idea/
|
.idea/
|
||||||
dist/
|
dist/
|
||||||
|
out/
|
20
.pre-commit-config.yaml
Normal file
20
.pre-commit-config.yaml
Normal 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
1
go.mod
|
@ -3,6 +3,7 @@ module github.com/baez90/kreaper
|
||||||
go 1.18
|
go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/maxatome/go-testdeep v1.11.0
|
||||||
go.uber.org/zap v1.21.0
|
go.uber.org/zap v1.21.0
|
||||||
k8s.io/api v0.23.5
|
k8s.io/api v0.23.5
|
||||||
k8s.io/apimachinery v0.23.5
|
k8s.io/apimachinery v0.23.5
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -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-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/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/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/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/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=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
|
12
main.go
12
main.go
|
@ -96,12 +96,18 @@ func prepareFlags() {
|
||||||
"Set target namespace in which kreaper will look for pods - env variable: KREAPER_TARGET_NAMESPACE",
|
"Set target namespace in which kreaper will look for pods - env variable: KREAPER_TARGET_NAMESPACE",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var kubeconfigFallback string
|
||||||
if home := homedir.HomeDir(); home != "" {
|
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")
|
kubeconfigFallback = filepath.Join(home, ".kube", "config")
|
||||||
} else {
|
|
||||||
flag.StringVar(&kubeconfig, "kubeconfig", lookupEnvOr("KUBECONFIG", "", identity[string]), "absolute path to the kubeconfig file")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flag.StringVar(
|
||||||
|
&kubeconfig,
|
||||||
|
"kubeconfig",
|
||||||
|
lookupEnvOr("KUBECONFIG", kubeconfigFallback, identity[string]),
|
||||||
|
"absolute path to the kubeconfig file",
|
||||||
|
)
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
165
reaper/reaper_test.go
Normal file
165
reaper/reaper_test.go
Normal 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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Reference in a new issue