-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add unit test for GarbageCollectorRunner
Signed-off-by: Ryotaro Banno <[email protected]>
- Loading branch information
1 parent
44add37
commit 320f305
Showing
1 changed file
with
178 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
package controller | ||
|
||
import ( | ||
"time" | ||
|
||
mantlev1 "github.com/cybozu-go/mantle/api/v1" | ||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
corev1 "k8s.io/api/core/v1" | ||
"k8s.io/apimachinery/pkg/types" | ||
) | ||
|
||
var _ = Describe("garbage collector", func() { | ||
var err error | ||
|
||
Context("isMantleRestoreAlreadyDeleted", func() { | ||
doTest := | ||
func( | ||
ctx SpecContext, | ||
buildMR func(ns string) *mantlev1.MantleRestore, | ||
buildPV func(ns string, mr *mantlev1.MantleRestore) *corev1.PersistentVolume, | ||
expectError, expectDeleted bool, | ||
) { | ||
runner := NewGarbageCollectorRunner(k8sClient, 1*time.Second) | ||
ns := resMgr.CreateNamespace() | ||
mr := buildMR(ns) | ||
if mr != nil { | ||
err = k8sClient.Create(ctx, mr) | ||
Expect(err).NotTo(HaveOccurred()) | ||
err = k8sClient.Get(ctx, types.NamespacedName{Name: mr.GetName(), Namespace: mr.GetNamespace()}, mr) | ||
Expect(err).NotTo(HaveOccurred()) | ||
} | ||
pv := buildPV(ns, mr) | ||
|
||
deleted, err := runner.isMantleRestoreAlreadyDeleted(ctx, pv) | ||
if expectError { | ||
Expect(err).To(HaveOccurred()) | ||
} else { | ||
Expect(err).NotTo(HaveOccurred()) | ||
} | ||
Expect(deleted).To(Equal(expectDeleted)) | ||
} | ||
|
||
makeMR := func(ns string) *mantlev1.MantleRestore { | ||
var mr mantlev1.MantleRestore | ||
mr.SetName("mr") | ||
mr.SetNamespace(ns) | ||
mr.Spec.Backup = "dummy" | ||
return &mr | ||
} | ||
|
||
makePV := func(ns string, mr *mantlev1.MantleRestore) *corev1.PersistentVolume { | ||
var pv corev1.PersistentVolume | ||
pv.SetAnnotations(map[string]string{ | ||
PVAnnotationRestoredBy: string(mr.GetUID()), | ||
PVAnnotationRestoredByName: "mr", | ||
PVAnnotationRestoredByNamespace: ns, | ||
}) | ||
return &pv | ||
} | ||
|
||
DescribeTable("isMantleRestoreAlreadyDeleted", | ||
doTest, | ||
Entry("MantleRestore exists", makeMR, makePV, false, false), | ||
Entry( | ||
"MantleRestore does NOT exist", | ||
func(ns string) *mantlev1.MantleRestore { return nil }, | ||
func(ns string, mr *mantlev1.MantleRestore) *corev1.PersistentVolume { | ||
var pv corev1.PersistentVolume | ||
pv.SetAnnotations(map[string]string{ | ||
PVAnnotationRestoredBy: "uid", | ||
PVAnnotationRestoredByName: "mr", | ||
PVAnnotationRestoredByNamespace: ns, | ||
}) | ||
return &pv | ||
}, | ||
false, true, | ||
), | ||
Entry( | ||
"MantleRestore exists, but the PV's annotation has unexpected MR's UID", | ||
makeMR, | ||
func(ns string, mr *mantlev1.MantleRestore) *corev1.PersistentVolume { | ||
pv := makePV(ns, mr) | ||
pv.Annotations[PVAnnotationRestoredBy] = "unexpected-uid" | ||
return pv | ||
}, | ||
false, true, | ||
), | ||
Entry( | ||
"PV annotation of restored-by missing", | ||
makeMR, | ||
func(ns string, mr *mantlev1.MantleRestore) *corev1.PersistentVolume { | ||
pv := makePV(ns, mr) | ||
delete(pv.Annotations, PVAnnotationRestoredBy) | ||
return pv | ||
}, | ||
true, false, | ||
), | ||
Entry( | ||
"PV annotation of restored-by-name missing", | ||
makeMR, | ||
func(ns string, mr *mantlev1.MantleRestore) *corev1.PersistentVolume { | ||
pv := makePV(ns, mr) | ||
delete(pv.Annotations, PVAnnotationRestoredByName) | ||
return pv | ||
}, | ||
true, false, | ||
), | ||
Entry( | ||
"PV annotation of restored-by-namespace missing", | ||
makeMR, | ||
func(ns string, mr *mantlev1.MantleRestore) *corev1.PersistentVolume { | ||
pv := makePV(ns, mr) | ||
delete(pv.Annotations, PVAnnotationRestoredByNamespace) | ||
return pv | ||
}, | ||
true, false, | ||
), | ||
) | ||
}) | ||
|
||
Context("deleteOrphanPVs", func() { | ||
It("should remove only orphan PVs", func(ctx SpecContext) { | ||
runner := NewGarbageCollectorRunner(k8sClient, 1*time.Second) | ||
ns := resMgr.CreateNamespace() | ||
|
||
mr1 := mantlev1.MantleRestore{} | ||
mr1.SetName("mr1") | ||
mr1.SetNamespace(ns) | ||
mr1.Spec.Backup = "dummy" | ||
err = k8sClient.Create(ctx, &mr1) | ||
Expect(err).NotTo(HaveOccurred()) | ||
err = k8sClient.Get(ctx, types.NamespacedName{Name: mr1.GetName(), Namespace: mr1.GetNamespace()}, &mr1) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
pv1, _, err := resMgr.CreateUniquePVAndPVC(ctx, ns) | ||
Expect(err).NotTo(HaveOccurred()) | ||
pv1.SetLabels(map[string]string{ | ||
labelRestoringPVKey: labelRestoringPVValue, | ||
}) | ||
pv1.SetAnnotations(map[string]string{ | ||
PVAnnotationRestoredBy: string(mr1.GetUID()), | ||
PVAnnotationRestoredByName: mr1.GetName(), | ||
PVAnnotationRestoredByNamespace: mr1.GetNamespace(), | ||
}) | ||
err = k8sClient.Update(ctx, pv1) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
pv2, _, err := resMgr.CreateUniquePVAndPVC(ctx, ns) | ||
Expect(err).NotTo(HaveOccurred()) | ||
pv2.SetLabels(map[string]string{ | ||
labelRestoringPVKey: labelRestoringPVValue, | ||
}) | ||
pv2.SetAnnotations(map[string]string{ | ||
PVAnnotationRestoredBy: "non-existing-uid", | ||
PVAnnotationRestoredByName: "non-existing-name", | ||
PVAnnotationRestoredByNamespace: "non-existing-namespace", | ||
}) | ||
err = k8sClient.Update(ctx, pv2) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
// No MantleRestore exists for pv2, so pv2 is orphan and should be removed. | ||
|
||
// Perform deleteOrphanPVs. | ||
err = runner.deleteOrphanPVs(ctx) | ||
Expect(err).NotTo(HaveOccurred()) | ||
|
||
// pv1 should NOT be deleted. | ||
err = k8sClient.Get(ctx, types.NamespacedName{Name: pv1.GetName()}, pv1) | ||
Expect(err).NotTo(HaveOccurred()) | ||
Expect(pv1.DeletionTimestamp.IsZero()).To(BeTrue()) | ||
// pv2 should be deleted. | ||
err = k8sClient.Get(ctx, types.NamespacedName{Name: pv2.GetName()}, pv2) | ||
Expect(err).NotTo(HaveOccurred()) | ||
Expect(pv2.DeletionTimestamp.IsZero()).To(BeFalse()) | ||
}) | ||
}) | ||
}) |