fix: Add context & timeouts to e2e tests

Tests will now each have a context that is cancelled on timeout.
BeforeEach and AfterEach blocks have their own timeouts, to allow
bounded setup and cleanup.

- Test Timeout: 5m
- Before Test Timeout: 30s
- After Test Timeout: 30s
This commit is contained in:
Karl Isenberg 2021-11-09 17:50:03 -08:00
parent b7f3c2a936
commit 5f80d35a70
12 changed files with 181 additions and 135 deletions

View File

@ -20,7 +20,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)
func applyAndDestroyTest(c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
func applyAndDestroyTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
By("Apply resources")
applier := invConfig.ApplierFactoryFunc()
inventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
@ -32,7 +32,7 @@ func applyAndDestroyTest(c client.Client, invConfig InventoryConfig, inventoryNa
deployment1Obj,
}
applierEvents := runCollect(applier.Run(context.TODO(), inventoryInfo, resources, apply.Options{
applierEvents := runCollect(applier.Run(ctx, inventoryInfo, resources, apply.Options{
ReconcileTimeout: 2 * time.Minute,
EmitStatusEvents: true,
}))
@ -184,16 +184,16 @@ func applyAndDestroyTest(c client.Client, invConfig InventoryConfig, inventoryNa
Expect(received).To(testutil.Equal(expEvents))
By("Verify deployment created")
assertUnstructuredExists(c, deployment1Obj)
assertUnstructuredExists(ctx, c, deployment1Obj)
By("Verify inventory")
invConfig.InvSizeVerifyFunc(c, inventoryName, namespaceName, inventoryID, 1)
invConfig.InvSizeVerifyFunc(ctx, c, inventoryName, namespaceName, inventoryID, 1)
By("Destroy resources")
destroyer := invConfig.DestroyerFactoryFunc()
options := apply.DestroyerOptions{InventoryPolicy: inventory.AdoptIfNoInventory}
destroyerEvents := runCollect(destroyer.Run(context.TODO(), inventoryInfo, options))
destroyerEvents := runCollect(destroyer.Run(ctx, inventoryInfo, options))
expEvents = []testutil.ExpEvent{
{
@ -271,7 +271,7 @@ func applyAndDestroyTest(c client.Client, invConfig InventoryConfig, inventoryNa
Expect(testutil.EventsToExpEvents(destroyerEvents)).To(testutil.Equal(expEvents))
By("Verify deployment deleted")
assertUnstructuredDoesNotExist(c, deployment1Obj)
assertUnstructuredDoesNotExist(ctx, c, deployment1Obj)
}
func createInventoryInfo(invConfig InventoryConfig, inventoryName, namespaceName, inventoryID string) inventory.InventoryInfo {

View File

@ -56,18 +56,18 @@ func withDependsOn(obj *unstructured.Unstructured, dep string) *unstructured.Uns
return obj
}
func deleteUnstructuredAndWait(c client.Client, obj *unstructured.Unstructured) {
func deleteUnstructuredAndWait(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
ref := mutation.NewResourceReference(obj)
err := c.Delete(context.TODO(), obj,
err := c.Delete(ctx, obj,
client.PropagationPolicy(metav1.DeletePropagationForeground))
Expect(err).NotTo(HaveOccurred(),
"expected DELETE to not error (%s): %s", ref, err)
waitForDeletion(c, obj)
waitForDeletion(ctx, c, obj)
}
func waitForDeletion(c client.Client, obj *unstructured.Unstructured) {
func waitForDeletion(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
ref := mutation.NewResourceReference(obj)
resultObj := ref.Unstructured()
@ -84,7 +84,7 @@ func waitForDeletion(c client.Client, obj *unstructured.Unstructured) {
Fail("timed out waiting for resource to be fully deleted")
return
case <-s.C:
err := c.Get(context.TODO(), types.NamespacedName{
err := c.Get(ctx, types.NamespacedName{
Namespace: obj.GetNamespace(),
Name: obj.GetName(),
}, resultObj)
@ -98,7 +98,17 @@ func waitForDeletion(c client.Client, obj *unstructured.Unstructured) {
}
}
func waitForCreation(c client.Client, obj *unstructured.Unstructured) {
func createUnstructuredAndWait(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
ref := mutation.NewResourceReference(obj)
err := c.Create(ctx, obj)
Expect(err).NotTo(HaveOccurred(),
"expected CREATE to not error (%s): %s", ref, err)
waitForCreation(ctx, c, obj)
}
func waitForCreation(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
ref := mutation.NewResourceReference(obj)
resultObj := ref.Unstructured()
@ -115,7 +125,7 @@ func waitForCreation(c client.Client, obj *unstructured.Unstructured) {
Fail("timed out waiting for resource to be fully created")
return
case <-s.C:
err := c.Get(context.TODO(), types.NamespacedName{
err := c.Get(ctx, types.NamespacedName{
Namespace: obj.GetNamespace(),
Name: obj.GetName(),
}, resultObj)
@ -130,11 +140,11 @@ func waitForCreation(c client.Client, obj *unstructured.Unstructured) {
}
}
func assertUnstructuredExists(c client.Client, obj *unstructured.Unstructured) *unstructured.Unstructured {
func assertUnstructuredExists(ctx context.Context, c client.Client, obj *unstructured.Unstructured) *unstructured.Unstructured {
ref := mutation.NewResourceReference(obj)
resultObj := ref.Unstructured()
err := c.Get(context.TODO(), types.NamespacedName{
err := c.Get(ctx, types.NamespacedName{
Namespace: obj.GetNamespace(),
Name: obj.GetName(),
}, resultObj)
@ -143,11 +153,11 @@ func assertUnstructuredExists(c client.Client, obj *unstructured.Unstructured) *
return resultObj
}
func assertUnstructuredDoesNotExist(c client.Client, obj *unstructured.Unstructured) {
func assertUnstructuredDoesNotExist(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
ref := mutation.NewResourceReference(obj)
resultObj := ref.Unstructured()
err := c.Get(context.TODO(), types.NamespacedName{
err := c.Get(ctx, types.NamespacedName{
Namespace: obj.GetNamespace(),
Name: obj.GetName(),
}, resultObj)

View File

@ -19,7 +19,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)
func continueOnErrorTest(c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
func continueOnErrorTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
By("apply an invalid CRD")
applier := invConfig.ApplierFactoryFunc()
@ -30,7 +30,7 @@ func continueOnErrorTest(c client.Client, invConfig InventoryConfig, inventoryNa
withNamespace(manifestToUnstructured(pod1), namespaceName),
}
applierEvents := runCollect(applier.Run(context.TODO(), inv, resources, apply.Options{}))
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.Options{}))
expEvents := []testutil.ExpEvent{
{
@ -140,8 +140,8 @@ func continueOnErrorTest(c client.Client, invConfig InventoryConfig, inventoryNa
Expect(receivedEvents).To(testutil.Equal(expEvents))
By("Verify pod1 created")
assertUnstructuredExists(c, withNamespace(manifestToUnstructured(pod1), namespaceName))
assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(pod1), namespaceName))
By("Verify CRD not created")
assertUnstructuredDoesNotExist(c, manifestToUnstructured(invalidCrd))
assertUnstructuredDoesNotExist(ctx, c, manifestToUnstructured(invalidCrd))
}

View File

@ -20,7 +20,7 @@ import (
)
//nolint:dupl // expEvents similar to mutation tests
func crdTest(_ client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
func crdTest(ctx context.Context, _ client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
By("apply a set of resources that includes both a crd and a cr")
applier := invConfig.ApplierFactoryFunc()
@ -34,7 +34,7 @@ func crdTest(_ client.Client, invConfig InventoryConfig, inventoryName, namespac
crdObj,
}
applierEvents := runCollect(applier.Run(context.TODO(), inv, resources, apply.Options{
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.Options{
ReconcileTimeout: 2 * time.Minute,
EmitStatusEvents: false,
}))
@ -215,7 +215,7 @@ func crdTest(_ client.Client, invConfig InventoryConfig, inventoryName, namespac
By("destroy the resources, including the crd")
destroyer := invConfig.DestroyerFactoryFunc()
options := apply.DestroyerOptions{InventoryPolicy: inventory.AdoptIfNoInventory}
destroyerEvents := runCollect(destroyer.Run(context.TODO(), inv, options))
destroyerEvents := runCollect(destroyer.Run(ctx, inv, options))
expEvents = []testutil.ExpEvent{
{

View File

@ -17,7 +17,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)
func deletionPreventionTest(c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
func deletionPreventionTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
By("Apply resources")
applier := invConfig.ApplierFactoryFunc()
inventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
@ -30,68 +30,68 @@ func deletionPreventionTest(c client.Client, invConfig InventoryConfig, inventor
withAnnotation(withNamespace(manifestToUnstructured(pod2), namespaceName), common.LifecycleDeleteAnnotation, common.PreventDeletion),
}
runCollect(applier.Run(context.TODO(), inventoryInfo, resources, apply.Options{
runCollect(applier.Run(ctx, inventoryInfo, resources, apply.Options{
ReconcileTimeout: 2 * time.Minute,
}))
By("Verify deployment created")
obj := assertUnstructuredExists(c, withNamespace(manifestToUnstructured(deployment1), namespaceName))
obj := assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(deployment1), namespaceName))
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
By("Verify pod1 created")
obj = assertUnstructuredExists(c, withNamespace(manifestToUnstructured(pod1), namespaceName))
obj = assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(pod1), namespaceName))
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
By("Verify pod2 created")
obj = assertUnstructuredExists(c, withNamespace(manifestToUnstructured(pod2), namespaceName))
obj = assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(pod2), namespaceName))
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
By("Verify the inventory size is 3")
invConfig.InvSizeVerifyFunc(c, inventoryName, namespaceName, inventoryID, 3)
invConfig.InvSizeVerifyFunc(ctx, c, inventoryName, namespaceName, inventoryID, 3)
resources = []*unstructured.Unstructured{
withNamespace(manifestToUnstructured(deployment1), namespaceName),
}
runCollect(applier.Run(context.TODO(), inventoryInfo, resources, apply.Options{
runCollect(applier.Run(ctx, inventoryInfo, resources, apply.Options{
ReconcileTimeout: 2 * time.Minute,
DryRunStrategy: common.DryRunClient,
}))
By("Verify deployment still exists and has the config.k8s.io/owning-inventory annotation")
obj = assertUnstructuredExists(c, withNamespace(manifestToUnstructured(deployment1), namespaceName))
obj = assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(deployment1), namespaceName))
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
By("Verify pod1 still exits and does not have the config.k8s.io/owning-inventory annotation")
obj = assertUnstructuredExists(c, withNamespace(manifestToUnstructured(pod1), namespaceName))
obj = assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(pod1), namespaceName))
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
By("Verify pod2 still exits and does not have the config.k8s.io/owning-inventory annotation")
obj = assertUnstructuredExists(c, withNamespace(manifestToUnstructured(pod2), namespaceName))
obj = assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(pod2), namespaceName))
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
By("Verify the inventory size is still 3")
invConfig.InvSizeVerifyFunc(c, inventoryName, namespaceName, inventoryID, 3)
invConfig.InvSizeVerifyFunc(ctx, c, inventoryName, namespaceName, inventoryID, 3)
resources = []*unstructured.Unstructured{
withNamespace(manifestToUnstructured(deployment1), namespaceName),
}
runCollect(applier.Run(context.TODO(), inventoryInfo, resources, apply.Options{
runCollect(applier.Run(ctx, inventoryInfo, resources, apply.Options{
ReconcileTimeout: 2 * time.Minute,
}))
By("Verify deployment still exists and has the config.k8s.io/owning-inventory annotation")
obj = assertUnstructuredExists(c, withNamespace(manifestToUnstructured(deployment1), namespaceName))
obj = assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(deployment1), namespaceName))
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(inventoryInfo.ID()))
By("Verify pod1 still exits and does not have the config.k8s.io/owning-inventory annotation")
obj = assertUnstructuredExists(c, withNamespace(manifestToUnstructured(pod1), namespaceName))
obj = assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(pod1), namespaceName))
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(""))
By("Verify pod2 still exits and does not have the config.k8s.io/owning-inventory annotation")
obj = assertUnstructuredExists(c, withNamespace(manifestToUnstructured(pod2), namespaceName))
obj = assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(pod2), namespaceName))
Expect(obj.GetAnnotations()[inventory.OwningInventoryKey]).To(Equal(""))
By("Verify the inventory size is 1")
invConfig.InvSizeVerifyFunc(c, inventoryName, namespaceName, inventoryID, 1)
invConfig.InvSizeVerifyFunc(ctx, c, inventoryName, namespaceName, inventoryID, 1)
}

View File

@ -18,7 +18,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)
func dependsOnTest(c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
func dependsOnTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
By("apply resources in order based on depends-on annotation")
applier := invConfig.ApplierFactoryFunc()
@ -36,7 +36,7 @@ func dependsOnTest(c client.Client, invConfig InventoryConfig, inventoryName, na
pod3Obj,
}
applierEvents := runCollect(applier.Run(context.TODO(), inv, resources, apply.Options{
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.Options{
EmitStatusEvents: false,
}))
@ -278,21 +278,21 @@ func dependsOnTest(c client.Client, invConfig InventoryConfig, inventoryName, na
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
By("verify pod1 created and ready")
result := assertUnstructuredExists(c, pod1Obj)
result := assertUnstructuredExists(ctx, c, pod1Obj)
podIP, found, err := testutil.NestedField(result.Object, "status", "podIP")
Expect(err).NotTo(HaveOccurred())
Expect(found).To(BeTrue())
Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
By("verify pod2 created and ready")
result = assertUnstructuredExists(c, pod2Obj)
result = assertUnstructuredExists(ctx, c, pod2Obj)
podIP, found, err = testutil.NestedField(result.Object, "status", "podIP")
Expect(err).NotTo(HaveOccurred())
Expect(found).To(BeTrue())
Expect(podIP).NotTo(BeEmpty()) // use podIP as proxy for readiness
By("verify pod3 created and ready")
result = assertUnstructuredExists(c, pod3Obj)
result = assertUnstructuredExists(ctx, c, pod3Obj)
podIP, found, err = testutil.NestedField(result.Object, "status", "podIP")
Expect(err).NotTo(HaveOccurred())
Expect(found).To(BeTrue())
@ -301,7 +301,7 @@ func dependsOnTest(c client.Client, invConfig InventoryConfig, inventoryName, na
By("destroy resources in opposite order")
destroyer := invConfig.DestroyerFactoryFunc()
options := apply.DestroyerOptions{InventoryPolicy: inventory.AdoptIfNoInventory}
destroyerEvents := runCollect(destroyer.Run(context.TODO(), inv, options))
destroyerEvents := runCollect(destroyer.Run(ctx, inv, options))
expEvents = []testutil.ExpEvent{
{
@ -523,11 +523,11 @@ func dependsOnTest(c client.Client, invConfig InventoryConfig, inventoryName, na
Expect(testutil.EventsToExpEvents(destroyerEvents)).To(testutil.Equal(expEvents))
By("verify pod1 deleted")
assertUnstructuredDoesNotExist(c, pod1Obj)
assertUnstructuredDoesNotExist(ctx, c, pod1Obj)
By("verify pod2 deleted")
assertUnstructuredDoesNotExist(c, pod2Obj)
assertUnstructuredDoesNotExist(ctx, c, pod2Obj)
By("verify pod3 deleted")
assertUnstructuredDoesNotExist(c, pod3Obj)
assertUnstructuredDoesNotExist(ctx, c, pod3Obj)
}

View File

@ -6,6 +6,7 @@ package e2e
import (
"context"
"fmt"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@ -34,8 +35,8 @@ type inventoryFactoryFunc func(name, namespace, id string) *unstructured.Unstruc
type invWrapperFunc func(*unstructured.Unstructured) inventory.InventoryInfo
type applierFactoryFunc func() *apply.Applier
type destroyerFactoryFunc func() *apply.Destroyer
type invSizeVerifyFunc func(c client.Client, name, namespace, id string, count int)
type invCountVerifyFunc func(c client.Client, namespace string, count int)
type invSizeVerifyFunc func(ctx context.Context, c client.Client, name, namespace, id string, count int)
type invCountVerifyFunc func(ctx context.Context, c client.Client, namespace string, count int)
type InventoryConfig struct {
InventoryStrategy inventory.InventoryStrategy
@ -82,6 +83,10 @@ func init() {
klog.SetOutput(GinkgoWriter)
}
var defaultTestTimeout = 5 * time.Minute
var defaultBeforeTestTimeout = 30 * time.Second
var defaultAfterTestTimeout = 30 * time.Second
var _ = Describe("Applier", func() {
var c client.Client
@ -102,11 +107,17 @@ var _ = Describe("Applier", func() {
})
Expect(err).NotTo(HaveOccurred())
createInventoryCRD(c)
ctx, cancel := context.WithTimeout(context.Background(), defaultBeforeTestTimeout)
defer cancel()
createInventoryCRD(ctx, c)
Expect(ctx.Err()).To(BeNil(), "BeforeSuite context cancelled or timed out")
})
AfterSuite(func() {
deleteInventoryCRD(c)
ctx, cancel := context.WithTimeout(context.Background(), defaultAfterTestTimeout)
defer cancel()
deleteInventoryCRD(ctx, c)
Expect(ctx.Err()).To(BeNil(), "AfterSuite context cancelled or timed out")
})
for name := range inventoryConfigs {
@ -115,13 +126,21 @@ var _ = Describe("Applier", func() {
Context("Apply and destroy", func() {
var namespace *v1.Namespace
var inventoryName string
var ctx context.Context
var cancel context.CancelFunc
BeforeEach(func() {
ctx, cancel = context.WithTimeout(context.Background(), defaultTestTimeout)
inventoryName = randomString("test-inv-")
namespace = createRandomNamespace(c)
namespace = createRandomNamespace(ctx, c)
})
AfterEach(func() {
Expect(ctx.Err()).To(BeNil(), "test context cancelled or timed out")
cancel()
// new timeout for cleanup
ctx, cancel = context.WithTimeout(context.Background(), defaultAfterTestTimeout)
defer cancel()
// clean up resources created by the tests
objs := []*unstructured.Unstructured{
manifestToUnstructured(cr),
@ -135,65 +154,74 @@ var _ = Describe("Applier", func() {
manifestToUnstructured(apiservice1),
}
for _, obj := range objs {
deleteUnstructuredIfExists(c, obj)
deleteUnstructuredIfExists(ctx, c, obj)
}
deleteNamespace(c, namespace)
deleteNamespace(ctx, c, namespace)
})
It("Apply and destroy", func() {
applyAndDestroyTest(c, invConfig, inventoryName, namespace.GetName())
applyAndDestroyTest(ctx, c, invConfig, inventoryName, namespace.GetName())
})
It("Deletion Prevention", func() {
deletionPreventionTest(c, invConfig, inventoryName, namespace.GetName())
deletionPreventionTest(ctx, c, invConfig, inventoryName, namespace.GetName())
})
It("Apply CRD and CR", func() {
crdTest(c, invConfig, inventoryName, namespace.GetName())
crdTest(ctx, c, invConfig, inventoryName, namespace.GetName())
})
It("Apply continues on error", func() {
continueOnErrorTest(c, invConfig, inventoryName, namespace.GetName())
continueOnErrorTest(ctx, c, invConfig, inventoryName, namespace.GetName())
})
It("Server-Side Apply", func() {
serversideApplyTest(c, invConfig, inventoryName, namespace.GetName())
serversideApplyTest(ctx, c, invConfig, inventoryName, namespace.GetName())
})
It("Implements depends-on apply ordering", func() {
dependsOnTest(c, invConfig, inventoryName, namespace.GetName())
dependsOnTest(ctx, c, invConfig, inventoryName, namespace.GetName())
})
It("Implements apply-time-mutation", func() {
mutationTest(c, invConfig, inventoryName, namespace.GetName())
mutationTest(ctx, c, invConfig, inventoryName, namespace.GetName())
})
It("Prune retrieval error correctly handled", func() {
pruneRetrieveErrorTest(c, invConfig, inventoryName, namespace.GetName())
pruneRetrieveErrorTest(ctx, c, invConfig, inventoryName, namespace.GetName())
})
})
Context("Inventory policy", func() {
var namespace *v1.Namespace
var ctx context.Context
var cancel context.CancelFunc
BeforeEach(func() {
namespace = createRandomNamespace(c)
ctx, cancel = context.WithTimeout(context.Background(), defaultTestTimeout)
namespace = createRandomNamespace(ctx, c)
})
AfterEach(func() {
deleteNamespace(c, namespace)
Expect(ctx.Err()).To(BeNil(), "test context cancelled or timed out")
cancel()
// new timeout for cleanup
ctx, cancel = context.WithTimeout(context.Background(), defaultAfterTestTimeout)
defer cancel()
deleteUnstructuredIfExists(ctx, c, withNamespace(manifestToUnstructured(deployment1), namespace.GetName()))
deleteNamespace(ctx, c, namespace)
})
It("MustMatch policy", func() {
inventoryPolicyMustMatchTest(c, invConfig, namespace.GetName())
inventoryPolicyMustMatchTest(ctx, c, invConfig, namespace.GetName())
})
It("AdoptIfNoInventory policy", func() {
inventoryPolicyAdoptIfNoInventoryTest(c, invConfig, namespace.GetName())
inventoryPolicyAdoptIfNoInventoryTest(ctx, c, invConfig, namespace.GetName())
})
It("AdoptAll policy", func() {
inventoryPolicyAdoptAllTest(c, invConfig, namespace.GetName())
inventoryPolicyAdoptAllTest(ctx, c, invConfig, namespace.GetName())
})
})
})
@ -202,36 +230,45 @@ var _ = Describe("Applier", func() {
Context("InventoryStrategy: Name", func() {
var namespace *v1.Namespace
var inventoryName string
var ctx context.Context
var cancel context.CancelFunc
BeforeEach(func() {
ctx, cancel = context.WithTimeout(context.Background(), defaultTestTimeout)
inventoryName = randomString("test-inv-")
namespace = createRandomNamespace(c)
namespace = createRandomNamespace(ctx, c)
})
AfterEach(func() {
deleteNamespace(c, namespace)
Expect(ctx.Err()).To(BeNil(), "test context cancelled or timed out")
cancel()
// new timeout for cleanup
ctx, cancel = context.WithTimeout(context.Background(), defaultAfterTestTimeout)
defer cancel()
deleteUnstructuredIfExists(ctx, c, withNamespace(manifestToUnstructured(deployment1), namespace.GetName()))
deleteNamespace(ctx, c, namespace)
})
It("Apply with existing inventory", func() {
applyWithExistingInvTest(c, inventoryConfigs[CustomTypeInvConfig], inventoryName, namespace.GetName())
applyWithExistingInvTest(ctx, c, inventoryConfigs[CustomTypeInvConfig], inventoryName, namespace.GetName())
})
})
})
func createInventoryCRD(c client.Client) {
func createInventoryCRD(ctx context.Context, c client.Client) {
invCRD := manifestToUnstructured(customprovider.InventoryCRD)
var u unstructured.Unstructured
u.SetGroupVersionKind(invCRD.GroupVersionKind())
err := c.Get(context.TODO(), types.NamespacedName{
err := c.Get(ctx, types.NamespacedName{
Name: invCRD.GetName(),
}, &u)
if apierrors.IsNotFound(err) {
err = c.Create(context.TODO(), invCRD)
err = c.Create(ctx, invCRD)
}
Expect(err).NotTo(HaveOccurred())
}
func createRandomNamespace(c client.Client) *v1.Namespace {
func createRandomNamespace(ctx context.Context, c client.Client) *v1.Namespace {
namespaceName := randomString("e2e-test-")
namespace := &v1.Namespace{
TypeMeta: metav1.TypeMeta{
@ -243,21 +280,21 @@ func createRandomNamespace(c client.Client) *v1.Namespace {
},
}
err := c.Create(context.TODO(), namespace)
err := c.Create(ctx, namespace)
Expect(err).ToNot(HaveOccurred())
return namespace
}
func deleteInventoryCRD(c client.Client) {
func deleteInventoryCRD(ctx context.Context, c client.Client) {
invCRD := manifestToUnstructured(customprovider.InventoryCRD)
err := c.Delete(context.TODO(), invCRD)
err := c.Delete(ctx, invCRD)
if err != nil && !apierrors.IsNotFound(err) {
Expect(err).ToNot(HaveOccurred())
}
}
func deleteUnstructuredIfExists(c client.Client, obj *unstructured.Unstructured) {
err := c.Delete(context.TODO(), obj)
func deleteUnstructuredIfExists(ctx context.Context, c client.Client, obj *unstructured.Unstructured) {
err := c.Delete(ctx, obj)
if err != nil {
Expect(err).To(Or(
BeAssignableToTypeOf(&meta.NoKindMatchError{}),
@ -269,8 +306,8 @@ func deleteUnstructuredIfExists(c client.Client, obj *unstructured.Unstructured)
}
}
func deleteNamespace(c client.Client, namespace *v1.Namespace) {
err := c.Delete(context.TODO(), namespace)
func deleteNamespace(ctx context.Context, c client.Client, namespace *v1.Namespace) {
err := c.Delete(ctx, namespace)
Expect(err).ToNot(HaveOccurred())
}
@ -282,9 +319,9 @@ func newDefaultInvDestroyer() *apply.Destroyer {
return newDestroyerFromInvFactory(inventory.ClusterInventoryClientFactory{})
}
func defaultInvSizeVerifyFunc(c client.Client, name, namespace, id string, count int) {
func defaultInvSizeVerifyFunc(ctx context.Context, c client.Client, name, namespace, id string, count int) {
var cmList v1.ConfigMapList
err := c.List(context.TODO(), &cmList,
err := c.List(ctx, &cmList,
client.MatchingLabels(map[string]string{common.InventoryLabel: id}),
client.InNamespace(namespace))
Expect(err).ToNot(HaveOccurred())
@ -297,9 +334,9 @@ func defaultInvSizeVerifyFunc(c client.Client, name, namespace, id string, count
Expect(len(data)).To(Equal(count))
}
func defaultInvCountVerifyFunc(c client.Client, namespace string, count int) {
func defaultInvCountVerifyFunc(ctx context.Context, c client.Client, namespace string, count int) {
var cmList v1.ConfigMapList
err := c.List(context.TODO(), &cmList, client.InNamespace(namespace), client.HasLabels{common.InventoryLabel})
err := c.List(ctx, &cmList, client.InNamespace(namespace), client.HasLabels{common.InventoryLabel})
Expect(err).NotTo(HaveOccurred())
Expect(len(cmList.Items)).To(Equal(count))
}
@ -320,10 +357,10 @@ func newFactory() util.Factory {
return util.NewFactory(matchVersionKubeConfigFlags)
}
func customInvSizeVerifyFunc(c client.Client, name, namespace, _ string, count int) {
func customInvSizeVerifyFunc(ctx context.Context, c client.Client, name, namespace, _ string, count int) {
var u unstructured.Unstructured
u.SetGroupVersionKind(customprovider.InventoryGVK)
err := c.Get(context.TODO(), types.NamespacedName{
err := c.Get(ctx, types.NamespacedName{
Name: name,
Namespace: namespace,
}, &u)
@ -340,10 +377,10 @@ func customInvSizeVerifyFunc(c client.Client, name, namespace, _ string, count i
Expect(len(s)).To(Equal(count))
}
func customInvCountVerifyFunc(c client.Client, namespace string, count int) {
func customInvCountVerifyFunc(ctx context.Context, c client.Client, namespace string, count int) {
var u unstructured.UnstructuredList
u.SetGroupVersionKind(customprovider.InventoryGVK)
err := c.List(context.TODO(), &u, client.InNamespace(namespace))
err := c.List(ctx, &u, client.InNamespace(namespace))
Expect(err).NotTo(HaveOccurred())
Expect(len(u.Items)).To(Equal(count))
}

View File

@ -20,7 +20,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)
func inventoryPolicyMustMatchTest(c client.Client, invConfig InventoryConfig, namespaceName string) {
func inventoryPolicyMustMatchTest(ctx context.Context, c client.Client, invConfig InventoryConfig, namespaceName string) {
By("Apply first set of resources")
applier := invConfig.ApplierFactoryFunc()
@ -31,7 +31,7 @@ func inventoryPolicyMustMatchTest(c client.Client, invConfig InventoryConfig, na
deployment1Obj,
}
runWithNoErr(applier.Run(context.TODO(), firstInv, firstResources, apply.Options{
runWithNoErr(applier.Run(ctx, firstInv, firstResources, apply.Options{
ReconcileTimeout: 2 * time.Minute,
EmitStatusEvents: true,
}))
@ -44,7 +44,7 @@ func inventoryPolicyMustMatchTest(c client.Client, invConfig InventoryConfig, na
withReplicas(deployment1Obj, 6),
}
applierEvents := runCollect(applier.Run(context.TODO(), secondInv, secondResources, apply.Options{
applierEvents := runCollect(applier.Run(ctx, secondInv, secondResources, apply.Options{
ReconcileTimeout: 2 * time.Minute,
EmitStatusEvents: true,
InventoryPolicy: inventory.InventoryPolicyMustMatch,
@ -178,20 +178,19 @@ func inventoryPolicyMustMatchTest(c client.Client, invConfig InventoryConfig, na
Expect(received).To(testutil.Equal(expEvents))
By("Verify resource wasn't updated")
result := assertUnstructuredExists(c, deployment1Obj)
result := assertUnstructuredExists(ctx, c, deployment1Obj)
replicas, found, err := testutil.NestedField(result.Object, "spec", "replicas")
Expect(err).NotTo(HaveOccurred())
Expect(found).To(BeTrue())
Expect(replicas).To(Equal(int64(4)))
invConfig.InvCountVerifyFunc(c, namespaceName, 2)
invConfig.InvCountVerifyFunc(ctx, c, namespaceName, 2)
}
func inventoryPolicyAdoptIfNoInventoryTest(c client.Client, invConfig InventoryConfig, namespaceName string) {
func inventoryPolicyAdoptIfNoInventoryTest(ctx context.Context, c client.Client, invConfig InventoryConfig, namespaceName string) {
By("Create unmanaged resource")
deployment1Obj := withNamespace(manifestToUnstructured(deployment1), namespaceName)
err := c.Create(context.TODO(), deployment1Obj)
Expect(err).NotTo(HaveOccurred())
createUnstructuredAndWait(ctx, c, deployment1Obj)
By("Apply resources")
applier := invConfig.ApplierFactoryFunc()
@ -203,7 +202,7 @@ func inventoryPolicyAdoptIfNoInventoryTest(c client.Client, invConfig InventoryC
withReplicas(deployment1Obj, 6),
}
applierEvents := runCollect(applier.Run(context.TODO(), inv, resources, apply.Options{
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.Options{
ReconcileTimeout: 2 * time.Minute,
EmitStatusEvents: true,
InventoryPolicy: inventory.AdoptIfNoInventory,
@ -345,7 +344,7 @@ func inventoryPolicyAdoptIfNoInventoryTest(c client.Client, invConfig InventoryC
Expect(received).To(testutil.Equal(expEvents))
By("Verify resource was updated and added to inventory")
result := assertUnstructuredExists(c, deployment1Obj)
result := assertUnstructuredExists(ctx, c, deployment1Obj)
replicas, found, err := testutil.NestedField(result.Object, "spec", "replicas")
Expect(err).NotTo(HaveOccurred())
@ -357,11 +356,11 @@ func inventoryPolicyAdoptIfNoInventoryTest(c client.Client, invConfig InventoryC
Expect(found).To(BeTrue())
Expect(value).To(Equal(invName))
invConfig.InvCountVerifyFunc(c, namespaceName, 1)
invConfig.InvSizeVerifyFunc(c, invName, namespaceName, invName, 1)
invConfig.InvCountVerifyFunc(ctx, c, namespaceName, 1)
invConfig.InvSizeVerifyFunc(ctx, c, invName, namespaceName, invName, 1)
}
func inventoryPolicyAdoptAllTest(c client.Client, invConfig InventoryConfig, namespaceName string) {
func inventoryPolicyAdoptAllTest(ctx context.Context, c client.Client, invConfig InventoryConfig, namespaceName string) {
By("Apply an initial set of resources")
applier := invConfig.ApplierFactoryFunc()
@ -372,7 +371,7 @@ func inventoryPolicyAdoptAllTest(c client.Client, invConfig InventoryConfig, nam
deployment1Obj,
}
runWithNoErr(applier.Run(context.TODO(), firstInv, firstResources, apply.Options{
runWithNoErr(applier.Run(ctx, firstInv, firstResources, apply.Options{
ReconcileTimeout: 2 * time.Minute,
EmitStatusEvents: true,
}))
@ -385,7 +384,7 @@ func inventoryPolicyAdoptAllTest(c client.Client, invConfig InventoryConfig, nam
withReplicas(deployment1Obj, 6),
}
applierEvents := runCollect(applier.Run(context.TODO(), secondInv, secondResources, apply.Options{
applierEvents := runCollect(applier.Run(ctx, secondInv, secondResources, apply.Options{
ReconcileTimeout: 2 * time.Minute,
EmitStatusEvents: true,
InventoryPolicy: inventory.AdoptAll,
@ -527,7 +526,7 @@ func inventoryPolicyAdoptAllTest(c client.Client, invConfig InventoryConfig, nam
Expect(received).To(testutil.Equal(expEvents))
By("Verify resource was updated and added to inventory")
result := assertUnstructuredExists(c, deployment1Obj)
result := assertUnstructuredExists(ctx, c, deployment1Obj)
replicas, found, err := testutil.NestedField(result.Object, "spec", "replicas")
Expect(err).NotTo(HaveOccurred())
@ -539,5 +538,5 @@ func inventoryPolicyAdoptAllTest(c client.Client, invConfig InventoryConfig, nam
Expect(found).To(BeTrue())
Expect(value).To(Equal(secondInvName))
invConfig.InvCountVerifyFunc(c, namespaceName, 2)
invConfig.InvCountVerifyFunc(ctx, c, namespaceName, 2)
}

View File

@ -32,7 +32,7 @@ import (
// port from pod-b into an environment variable of pod-a.
//nolint:dupl // expEvents similar to CRD tests
func mutationTest(c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
func mutationTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
By("apply resources in order with substitutions based on apply-time-mutation annotation")
applier := invConfig.ApplierFactoryFunc()
@ -48,7 +48,7 @@ func mutationTest(c client.Client, invConfig InventoryConfig, inventoryName, nam
podBObj,
}
applierEvents := runCollect(applier.Run(context.TODO(), inv, resources, apply.Options{
applierEvents := runCollect(applier.Run(ctx, inv, resources, apply.Options{
EmitStatusEvents: false,
}))
@ -226,7 +226,7 @@ func mutationTest(c client.Client, invConfig InventoryConfig, inventoryName, nam
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
By("verify podB is created and ready")
result := assertUnstructuredExists(c, podBObj)
result := assertUnstructuredExists(ctx, c, podBObj)
podIP, found, err := testutil.NestedField(result.Object, "status", "podIP")
Expect(err).NotTo(HaveOccurred())
@ -241,7 +241,7 @@ func mutationTest(c client.Client, invConfig InventoryConfig, inventoryName, nam
host := fmt.Sprintf("%s:%d", podIP, containerPort)
By("verify podA is mutated, created, and ready")
result = assertUnstructuredExists(c, podAObj)
result = assertUnstructuredExists(ctx, c, podAObj)
podIP, found, err = testutil.NestedField(result.Object, "status", "podIP")
Expect(err).NotTo(HaveOccurred())
@ -256,7 +256,7 @@ func mutationTest(c client.Client, invConfig InventoryConfig, inventoryName, nam
By("destroy resources in opposite order")
destroyer := invConfig.DestroyerFactoryFunc()
options := apply.DestroyerOptions{InventoryPolicy: inventory.AdoptIfNoInventory}
destroyerEvents := runCollect(destroyer.Run(context.TODO(), inv, options))
destroyerEvents := runCollect(destroyer.Run(ctx, inv, options))
expEvents = []testutil.ExpEvent{
{
@ -415,8 +415,8 @@ func mutationTest(c client.Client, invConfig InventoryConfig, inventoryName, nam
Expect(testutil.EventsToExpEvents(destroyerEvents)).To(testutil.Equal(expEvents))
By("verify podB deleted")
assertUnstructuredDoesNotExist(c, podBObj)
assertUnstructuredDoesNotExist(ctx, c, podBObj)
By("verify podA deleted")
assertUnstructuredDoesNotExist(c, podAObj)
assertUnstructuredDoesNotExist(ctx, c, podAObj)
}

View File

@ -15,7 +15,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)
func applyWithExistingInvTest(c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
func applyWithExistingInvTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
By("Apply first set of resources")
applier := invConfig.ApplierFactoryFunc()
orgInventoryID := fmt.Sprintf("%s-%s", inventoryName, namespaceName)
@ -26,19 +26,19 @@ func applyWithExistingInvTest(c client.Client, invConfig InventoryConfig, invent
withNamespace(manifestToUnstructured(deployment1), namespaceName),
}
runWithNoErr(applier.Run(context.TODO(), orgApplyInv, resources, apply.Options{
runWithNoErr(applier.Run(ctx, orgApplyInv, resources, apply.Options{
ReconcileTimeout: 2 * time.Minute,
EmitStatusEvents: true,
}))
By("Verify inventory")
invConfig.InvSizeVerifyFunc(c, inventoryName, namespaceName, orgInventoryID, 1)
invConfig.InvSizeVerifyFunc(ctx, c, inventoryName, namespaceName, orgInventoryID, 1)
By("Apply second set of resources, using same inventory name but different ID")
secondInventoryID := fmt.Sprintf("%s-%s-2", inventoryName, namespaceName)
secondApplyInv := invConfig.InvWrapperFunc(invConfig.InventoryFactoryFunc(inventoryName, namespaceName, secondInventoryID))
err := run(applier.Run(context.TODO(), secondApplyInv, resources, apply.Options{
err := run(applier.Run(ctx, secondApplyInv, resources, apply.Options{
ReconcileTimeout: 2 * time.Minute,
EmitStatusEvents: true,
}))

View File

@ -18,7 +18,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)
func pruneRetrieveErrorTest(c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
func pruneRetrieveErrorTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
By("apply a single resource, which is referenced in the inventory")
applier := invConfig.ApplierFactoryFunc()
@ -30,7 +30,7 @@ func pruneRetrieveErrorTest(c client.Client, invConfig InventoryConfig, inventor
withNamespace(manifestToUnstructured(pod1), namespaceName),
}
applierEvents := runCollect(applier.Run(context.TODO(), inv, resource1, apply.Options{
applierEvents := runCollect(applier.Run(ctx, inv, resource1, apply.Options{
EmitStatusEvents: false,
}))
@ -127,22 +127,22 @@ func pruneRetrieveErrorTest(c client.Client, invConfig InventoryConfig, inventor
Expect(testutil.EventsToExpEvents(applierEvents)).To(testutil.Equal(expEvents))
By("Verify pod1 created")
assertUnstructuredExists(c, withNamespace(manifestToUnstructured(pod1), namespaceName))
assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(pod1), namespaceName))
// Delete the previously applied resource, which is referenced in the inventory.
By("delete resource, which is referenced in the inventory")
deleteUnstructuredAndWait(c, withNamespace(manifestToUnstructured(pod1), namespaceName))
deleteUnstructuredAndWait(ctx, c, withNamespace(manifestToUnstructured(pod1), namespaceName))
By("Verify inventory")
// The inventory should still have the previously deleted item.
invConfig.InvSizeVerifyFunc(c, inventoryName, namespaceName, inventoryID, 1)
invConfig.InvSizeVerifyFunc(ctx, c, inventoryName, namespaceName, inventoryID, 1)
By("apply a different resource, and validate the inventory accurately reflects only this object")
resource2 := []*unstructured.Unstructured{
withNamespace(manifestToUnstructured(pod2), namespaceName),
}
applierEvents2 := runCollect(applier.Run(context.TODO(), inv, resource2, apply.Options{
applierEvents2 := runCollect(applier.Run(ctx, inv, resource2, apply.Options{
EmitStatusEvents: false,
}))
@ -241,20 +241,20 @@ func pruneRetrieveErrorTest(c client.Client, invConfig InventoryConfig, inventor
By("Wait for pod2 to be created")
// TODO: change behavior so the user doesn't need to code their own wait
waitForCreation(c, withNamespace(manifestToUnstructured(pod2), namespaceName))
waitForCreation(ctx, c, withNamespace(manifestToUnstructured(pod2), namespaceName))
By("Verify pod1 still deleted")
assertUnstructuredDoesNotExist(c, withNamespace(manifestToUnstructured(pod1), namespaceName))
assertUnstructuredDoesNotExist(ctx, c, withNamespace(manifestToUnstructured(pod1), namespaceName))
By("Verify inventory")
// The inventory should only have the currently applied item.
invConfig.InvSizeVerifyFunc(c, inventoryName, namespaceName, inventoryID, 1)
invConfig.InvSizeVerifyFunc(ctx, c, inventoryName, namespaceName, inventoryID, 1)
By("Destroy resources")
destroyer := invConfig.DestroyerFactoryFunc()
options := apply.DestroyerOptions{InventoryPolicy: inventory.AdoptIfNoInventory}
destroyerEvents := runCollect(destroyer.Run(context.TODO(), inv, options))
destroyerEvents := runCollect(destroyer.Run(ctx, inv, options))
expEvents3 := []testutil.ExpEvent{
{
@ -331,9 +331,9 @@ func pruneRetrieveErrorTest(c client.Client, invConfig InventoryConfig, inventor
Expect(testutil.EventsToExpEvents(destroyerEvents)).To(testutil.Equal(expEvents3))
By("Verify pod1 is deleted")
assertUnstructuredDoesNotExist(c, withNamespace(manifestToUnstructured(pod1), namespaceName))
assertUnstructuredDoesNotExist(ctx, c, withNamespace(manifestToUnstructured(pod1), namespaceName))
By("Wait for pod2 to be deleted")
// TODO: change behavior so the user doesn't need to code their own wait
waitForDeletion(c, withNamespace(manifestToUnstructured(pod2), namespaceName))
waitForDeletion(ctx, c, withNamespace(manifestToUnstructured(pod2), namespaceName))
}

View File

@ -17,7 +17,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)
func serversideApplyTest(c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
func serversideApplyTest(ctx context.Context, c client.Client, invConfig InventoryConfig, inventoryName, namespaceName string) {
By("Apply a Deployment and an APIService by server-side apply")
applier := invConfig.ApplierFactoryFunc()
@ -27,7 +27,7 @@ func serversideApplyTest(c client.Client, invConfig InventoryConfig, inventoryNa
manifestToUnstructured(apiservice1),
}
runWithNoErr(applier.Run(context.TODO(), inv, firstResources, apply.Options{
runWithNoErr(applier.Run(ctx, inv, firstResources, apply.Options{
ReconcileTimeout: 2 * time.Minute,
EmitStatusEvents: true,
ServerSideOptions: common.ServerSideOptions{
@ -38,7 +38,7 @@ func serversideApplyTest(c client.Client, invConfig InventoryConfig, inventoryNa
}))
By("Verify deployment is server-side applied")
result := assertUnstructuredExists(c, withNamespace(manifestToUnstructured(deployment1), namespaceName))
result := assertUnstructuredExists(ctx, c, withNamespace(manifestToUnstructured(deployment1), namespaceName))
// LastAppliedConfigAnnotation annotation is only set for client-side apply and we've server-side applied here.
_, found, err := testutil.NestedField(result.Object, "metadata", "annotations", v1.LastAppliedConfigAnnotation)
@ -51,7 +51,7 @@ func serversideApplyTest(c client.Client, invConfig InventoryConfig, inventoryNa
Expect(manager).To(Equal("test"))
By("Verify APIService is server-side applied")
result = assertUnstructuredExists(c, manifestToUnstructured(apiservice1))
result = assertUnstructuredExists(ctx, c, manifestToUnstructured(apiservice1))
// LastAppliedConfigAnnotation annotation is only set for client-side apply and we've server-side applied here.
_, found, err = testutil.NestedField(result.Object, "metadata", "annotations", v1.LastAppliedConfigAnnotation)