418 lines
13 KiB
Go
418 lines
13 KiB
Go
/*
|
|
Copyright 2021 The cert-manager Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package revisionmanager
|
|
|
|
import (
|
|
"context"
|
|
"reflect"
|
|
"testing"
|
|
|
|
logtesting "github.com/go-logr/logr/testing"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
"k8s.io/apimachinery/pkg/types"
|
|
coretesting "k8s.io/client-go/testing"
|
|
|
|
cmapi "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
|
|
cmmeta "github.com/cert-manager/cert-manager/pkg/apis/meta/v1"
|
|
controllerpkg "github.com/cert-manager/cert-manager/pkg/controller"
|
|
testpkg "github.com/cert-manager/cert-manager/pkg/controller/test"
|
|
"github.com/cert-manager/cert-manager/test/unit/gen"
|
|
)
|
|
|
|
func TestProcessItem(t *testing.T) {
|
|
baseCrt := gen.Certificate("test-cert",
|
|
gen.SetCertificateNamespace("testns"),
|
|
gen.SetCertificateUID("uid-1"),
|
|
)
|
|
baseCRNoOwner := gen.CertificateRequest("test-cr",
|
|
gen.SetCertificateRequestNamespace("testns"),
|
|
)
|
|
baseCR := gen.CertificateRequestFrom(baseCRNoOwner,
|
|
gen.AddCertificateRequestOwnerReferences(*metav1.NewControllerRef(
|
|
baseCrt, cmapi.SchemeGroupVersion.WithKind("Certificate")),
|
|
),
|
|
)
|
|
|
|
tests := map[string]struct {
|
|
// key that should be passed to ProcessItem.
|
|
// if not set, the 'namespace/name' of the 'Certificate' field will be used.
|
|
// if neither is set, the key will be ""
|
|
key string
|
|
|
|
// Certificate to be synced for the test.
|
|
// if not set, the 'key' will be passed to ProcessItem instead.
|
|
certificate *cmapi.Certificate
|
|
|
|
// Request, if set, will exist in the apiserver before the test is run.
|
|
requests []runtime.Object
|
|
|
|
expectedActions []testpkg.Action
|
|
|
|
// err is the expected error text returned by the controller, if any.
|
|
err string
|
|
}{
|
|
"do nothing if an empty 'key' is used": {},
|
|
"do nothing if an invalid 'key' is used": {
|
|
key: "abc/def/ghi",
|
|
},
|
|
"do nothing if a key references a Certificate that does not exist": {
|
|
key: "namespace/name",
|
|
},
|
|
"do nothing if Certificate is not in a Ready=True state": {
|
|
certificate: gen.CertificateFrom(baseCrt,
|
|
gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionIssuing, Status: cmmeta.ConditionFalse}),
|
|
gen.SetCertificateRevisionHistoryLimit(1),
|
|
),
|
|
requests: []runtime.Object{
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-1"),
|
|
gen.SetCertificateRequestRevision("1"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("2"),
|
|
),
|
|
},
|
|
},
|
|
"do nothing if no requests exist": {
|
|
certificate: gen.CertificateFrom(baseCrt,
|
|
gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
|
|
gen.SetCertificateRevisionHistoryLimit(1),
|
|
),
|
|
},
|
|
"do nothing if requests don't have or bad revisions set": {
|
|
certificate: gen.CertificateFrom(baseCrt,
|
|
gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
|
|
gen.SetCertificateRevisionHistoryLimit(1),
|
|
),
|
|
requests: []runtime.Object{
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-1"),
|
|
gen.SetCertificateRequestRevision("abc"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-2"),
|
|
),
|
|
},
|
|
},
|
|
"do nothing if requests aren't owned by this Certificate": {
|
|
certificate: gen.CertificateFrom(baseCrt,
|
|
gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
|
|
gen.SetCertificateRevisionHistoryLimit(1),
|
|
),
|
|
requests: []runtime.Object{
|
|
gen.CertificateRequestFrom(baseCRNoOwner,
|
|
gen.SetCertificateRequestName("cr-1"),
|
|
gen.SetCertificateRequestRevision("1"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCRNoOwner,
|
|
gen.SetCertificateRequestName("cr-2"),
|
|
gen.SetCertificateRequestRevision("2"),
|
|
),
|
|
},
|
|
},
|
|
"do nothing if number of revisions matches that of the limit": {
|
|
certificate: gen.CertificateFrom(baseCrt,
|
|
gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
|
|
gen.SetCertificateRevisionHistoryLimit(2),
|
|
),
|
|
requests: []runtime.Object{
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-1"),
|
|
gen.SetCertificateRequestRevision("1"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-2"),
|
|
gen.SetCertificateRequestRevision("2"),
|
|
),
|
|
},
|
|
},
|
|
"do nothing if revision limit is not set": {
|
|
certificate: gen.CertificateFrom(baseCrt,
|
|
gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
|
|
),
|
|
requests: []runtime.Object{
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-1"),
|
|
gen.SetCertificateRequestRevision("1"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-2"),
|
|
gen.SetCertificateRequestRevision("2"),
|
|
),
|
|
},
|
|
},
|
|
"delete 1 request if limit is 1 and 2 requests exist": {
|
|
certificate: gen.CertificateFrom(baseCrt,
|
|
gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
|
|
gen.SetCertificateRevisionHistoryLimit(1),
|
|
),
|
|
requests: []runtime.Object{
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-2"),
|
|
gen.SetCertificateRequestRevision("2"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-1"),
|
|
gen.SetCertificateRequestRevision("1"),
|
|
),
|
|
},
|
|
expectedActions: []testpkg.Action{
|
|
testpkg.NewAction(coretesting.NewDeleteAction(cmapi.SchemeGroupVersion.WithResource("certificaterequests"), "testns", "cr-1")),
|
|
},
|
|
},
|
|
"delete 3 requests if limit is 3 and 6 requests exist": {
|
|
certificate: gen.CertificateFrom(baseCrt,
|
|
gen.SetCertificateStatusCondition(cmapi.CertificateCondition{Type: cmapi.CertificateConditionReady, Status: cmmeta.ConditionTrue}),
|
|
gen.SetCertificateRevisionHistoryLimit(3),
|
|
),
|
|
requests: []runtime.Object{
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-2"),
|
|
gen.SetCertificateRequestRevision("2"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-3"),
|
|
gen.SetCertificateRequestRevision("3"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-1"),
|
|
gen.SetCertificateRequestRevision("1"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-4"),
|
|
gen.SetCertificateRequestRevision("11"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-5"),
|
|
gen.SetCertificateRequestRevision("11"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-6"),
|
|
gen.SetCertificateRequestRevision("2"),
|
|
),
|
|
},
|
|
expectedActions: []testpkg.Action{
|
|
testpkg.NewAction(coretesting.NewDeleteAction(cmapi.SchemeGroupVersion.WithResource("certificaterequests"), "testns", "cr-1")),
|
|
testpkg.NewAction(coretesting.NewDeleteAction(cmapi.SchemeGroupVersion.WithResource("certificaterequests"), "testns", "cr-2")),
|
|
testpkg.NewAction(coretesting.NewDeleteAction(cmapi.SchemeGroupVersion.WithResource("certificaterequests"), "testns", "cr-6")),
|
|
},
|
|
},
|
|
}
|
|
for name, test := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
// Create and initialise a new unit test builder
|
|
builder := &testpkg.Builder{
|
|
T: t,
|
|
ExpectedEvents: nil,
|
|
ExpectedActions: test.expectedActions,
|
|
StringGenerator: func(i int) string { return "notrandom" },
|
|
}
|
|
if test.certificate != nil {
|
|
builder.CertManagerObjects = append(builder.CertManagerObjects, test.certificate)
|
|
}
|
|
builder.CertManagerObjects = append(builder.CertManagerObjects, test.requests...)
|
|
builder.Init()
|
|
|
|
// Register informers used by the controller using the registration wrapper
|
|
w := &controllerWrapper{}
|
|
_, _, err := w.Register(builder.Context)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Start the informers and begin processing updates
|
|
builder.Start()
|
|
defer builder.Stop()
|
|
|
|
key := test.key
|
|
if key == "" && test.certificate != nil {
|
|
key, err = controllerpkg.KeyFunc(test.certificate)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// Call ProcessItem
|
|
err = w.controller.ProcessItem(context.Background(), key)
|
|
switch {
|
|
case err != nil:
|
|
if test.err != err.Error() {
|
|
t.Errorf("error text did not match, got=%s, exp=%s", err.Error(), test.err)
|
|
}
|
|
default:
|
|
if test.err != "" {
|
|
t.Errorf("got no error but expected: %s", test.err)
|
|
}
|
|
}
|
|
|
|
if err := builder.AllEventsCalled(); err != nil {
|
|
builder.T.Error(err)
|
|
}
|
|
if err := builder.AllActionsExecuted(); err != nil {
|
|
builder.T.Error(err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCertificateRequestsToDelete(t *testing.T) {
|
|
baseCR := gen.CertificateRequest("test")
|
|
|
|
tests := map[string]struct {
|
|
input []*cmapi.CertificateRequest
|
|
limit int
|
|
exp []revision
|
|
}{
|
|
"an empty list of request should return empty": {
|
|
input: nil,
|
|
limit: 3,
|
|
exp: nil,
|
|
},
|
|
"a single request with no revision set should return empty": {
|
|
input: []*cmapi.CertificateRequest{
|
|
baseCR,
|
|
},
|
|
limit: 3,
|
|
exp: nil,
|
|
},
|
|
"a single request with revision set but higher limit should return no requests": {
|
|
input: []*cmapi.CertificateRequest{
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestRevision("123"),
|
|
),
|
|
},
|
|
limit: 3,
|
|
exp: nil,
|
|
},
|
|
"two requests with one badly formed revision but limit set to 1 should return no requests": {
|
|
input: []*cmapi.CertificateRequest{
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-1"),
|
|
gen.SetCertificateRequestRevision("123"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-2"),
|
|
gen.SetCertificateRequestRevision("hello"),
|
|
),
|
|
},
|
|
limit: 1,
|
|
exp: []revision{},
|
|
},
|
|
"multiple requests with some with good revsions should return list in order": {
|
|
input: []*cmapi.CertificateRequest{
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-1"),
|
|
gen.SetCertificateRequestRevision("123"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-2"),
|
|
gen.SetCertificateRequestRevision("hello"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-3"),
|
|
gen.SetCertificateRequestRevision("3"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-4"),
|
|
gen.SetCertificateRequestRevision("cert-manager"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-5"),
|
|
gen.SetCertificateRequestRevision("900"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-6"),
|
|
gen.SetCertificateRequestRevision("1"),
|
|
),
|
|
},
|
|
limit: 1,
|
|
exp: []revision{
|
|
{
|
|
1,
|
|
types.NamespacedName{
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Name: "cr-6",
|
|
},
|
|
},
|
|
{
|
|
3,
|
|
types.NamespacedName{
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Name: "cr-3",
|
|
},
|
|
},
|
|
{
|
|
123,
|
|
types.NamespacedName{
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Name: "cr-1",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
"multiple requests with some with good revsions but less than the limit, should return list in order under limit": {
|
|
input: []*cmapi.CertificateRequest{
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-1"),
|
|
gen.SetCertificateRequestRevision("123"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-2"),
|
|
gen.SetCertificateRequestRevision("hello"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-3"),
|
|
gen.SetCertificateRequestRevision("3"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-4"),
|
|
gen.SetCertificateRequestRevision("cert-manager"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-5"),
|
|
gen.SetCertificateRequestRevision("900"),
|
|
),
|
|
gen.CertificateRequestFrom(baseCR,
|
|
gen.SetCertificateRequestName("cr-6"),
|
|
gen.SetCertificateRequestRevision("1"),
|
|
),
|
|
},
|
|
limit: 3,
|
|
exp: []revision{
|
|
{
|
|
1,
|
|
types.NamespacedName{
|
|
Namespace: gen.DefaultTestNamespace,
|
|
Name: "cr-6",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for name, test := range tests {
|
|
t.Run(name, func(t *testing.T) {
|
|
log := logtesting.NewTestLogger(t)
|
|
output := certificateRequestsToDelete(log, test.limit, test.input)
|
|
if !reflect.DeepEqual(test.exp, output) {
|
|
t.Errorf("unexpected prune sort response, exp=%v got=%v",
|
|
test.exp, output)
|
|
}
|
|
})
|
|
}
|
|
}
|