Merge pull request #331 from ankeesler/1-20-owner-ref-test

Update test/integration/kubeclient_test.go to work with Kube 1.20 GC behavior
This commit is contained in:
Andrew Keesler 2021-01-14 10:59:02 -05:00 committed by GitHub
commit 434448a2f9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 28 deletions

View File

@ -136,30 +136,44 @@ func TestKubeClientOwnerRef(t *testing.T) {
return err
})
// sanity check API service client
apiService, err := ownerRefClient.Aggregation.ApiregistrationV1().APIServices().Create(
ctx,
&apiregistrationv1.APIService{
ObjectMeta: metav1.ObjectMeta{
Name: "v1.pandas.dev",
OwnerReferences: nil, // no owner refs set
// TODO: update middleware code to not set owner references on cluster-scoped objects.
//
// The Kube 1.20 garbage collector asserts some new behavior in regards to invalid owner
// references (i.e., when you have a namespace-scoped owner references for a cluster-scoped
// dependent, the cluster-scoped dependent is not removed). We also found a bug in the 1.20
// garbage collector where namespace-scoped dependents are not garbage collected if their owner
// had been used as an invalid owner reference before - this bug causes our test to fallover
// because we are setting a namespace-scoped owner ref on this APIService.
//
// We believe that the best way to get around this problem is to update our kubeclient code to
// never set owner references on cluster-scoped objects. After we do that, we will uncomment this
// part of the test.
if false {
// sanity check API service client
apiService, err := ownerRefClient.Aggregation.ApiregistrationV1().APIServices().Create(
ctx,
&apiregistrationv1.APIService{
ObjectMeta: metav1.ObjectMeta{
Name: "v1.pandas.dev",
OwnerReferences: nil, // no owner refs set
},
Spec: apiregistrationv1.APIServiceSpec{
Version: "v1",
Group: "pandas.dev",
GroupPriorityMinimum: 10_000,
VersionPriority: 500,
},
},
Spec: apiregistrationv1.APIServiceSpec{
Version: "v1",
Group: "pandas.dev",
GroupPriorityMinimum: 10_000,
VersionPriority: 500,
},
},
metav1.CreateOptions{},
)
require.NoError(t, err)
hasOwnerRef(t, apiService, ref)
// this owner ref is invalid for an API service so it should be immediately deleted
isEventuallyDeleted(t, func() error {
_, err := ownerRefClient.Aggregation.ApiregistrationV1().APIServices().Get(ctx, apiService.Name, metav1.GetOptions{})
return err
})
metav1.CreateOptions{},
)
require.NoError(t, err)
hasOwnerRef(t, apiService, ref)
// this owner ref is invalid for an API service so it should be immediately deleted
isEventuallyDeleted(t, func() error {
_, err := ownerRefClient.Aggregation.ApiregistrationV1().APIServices().Get(ctx, apiService.Name, metav1.GetOptions{})
return err
})
}
// sanity check concierge client
credentialIssuer, err := ownerRefClient.PinnipedConcierge.ConfigV1alpha1().CredentialIssuers(namespace.Name).Create(
@ -244,16 +258,15 @@ func hasOwnerRef(t *testing.T, obj metav1.Object, ref metav1.OwnerReference) {
func isEventuallyDeleted(t *testing.T, f func() error) {
t.Helper()
require.Eventually(t, func() bool {
library.RequireEventuallyWithoutError(t, func() (bool, error) {
err := f()
switch {
case err == nil:
return false
return false, nil
case errors.IsNotFound(err):
return true
return true, nil
default:
require.NoError(t, err)
return false
return false, err
}
}, time.Minute, time.Second)
}

View File

@ -0,0 +1,26 @@
// Copyright 2021 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package library
import (
"testing"
"time"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/util/wait"
)
// RequireEventuallyWithoutError is a wrapper around require.Eventually() that allows the caller to
// return an error from the condition function. If the condition function returns an error at any
// point, the assertion will immediately fail.
func RequireEventuallyWithoutError(
t *testing.T,
f func() (bool, error),
waitFor time.Duration,
tick time.Duration,
msgAndArgs ...interface{},
) {
t.Helper()
require.NoError(t, wait.PollImmediate(tick, waitFor, f), msgAndArgs...)
}