Add integration and more unit tests

- Add integration test for serving cert auto-generation and rotation
- Add unit test for `WithInitialEvent` of the cert manager controller
- Move UpdateAPIService() into the `apicerts` package, since that is
  the only user of the function.
This commit is contained in:
Ryan Richard
2020-08-11 10:14:57 -07:00
parent 8034ef24ff
commit fadd718d08
12 changed files with 304 additions and 16 deletions
@@ -19,7 +19,6 @@ import (
aggregatorclient "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"
"github.com/suzerain-io/controller-go"
"github.com/suzerain-io/placeholder-name/internal/autoregistration"
"github.com/suzerain-io/placeholder-name/internal/certauthority"
placeholdernamecontroller "github.com/suzerain-io/placeholder-name/internal/controller"
)
@@ -45,6 +44,7 @@ func NewCertsManagerController(
aggregatorClient aggregatorclient.Interface,
secretInformer corev1informers.SecretInformer,
withInformer placeholdernamecontroller.WithInformerOptionFunc,
withInitialEvent placeholdernamecontroller.WithInitialEventOptionFunc,
) controller.Controller {
return controller.New(
controller.Config{
@@ -62,7 +62,7 @@ func NewCertsManagerController(
controller.InformerOption{},
),
// Be sure to run once even if the Secret that the informer is watching doesn't exist.
controller.WithInitialEvent(controller.Key{
withInitialEvent(controller.Key{
Namespace: namespace,
Name: certsSecretName,
}),
@@ -123,7 +123,7 @@ func (c *certsManagerController) Sync(ctx controller.Context) error {
}
// Update the APIService to give it the new CA bundle.
if err := autoregistration.UpdateAPIService(ctx.Context, c.aggregatorClient, aggregatedAPIServerCA.Bundle()); err != nil {
if err := UpdateAPIService(ctx.Context, c.aggregatorClient, aggregatedAPIServerCA.Bundle()); err != nil {
return fmt.Errorf("could not update the API service: %w", err)
}
@@ -31,26 +31,27 @@ import (
placeholderv1alpha1 "github.com/suzerain-io/placeholder-name/kubernetes/1.19/api/apis/placeholder/v1alpha1"
)
// TODO test that it uses controller.WithInitialEvent correctly
func TestManagerControllerInformerFilters(t *testing.T) {
spec.Run(t, "informer filters", func(t *testing.T, when spec.G, it spec.S) {
func TestManagerControllerOptions(t *testing.T) {
spec.Run(t, "options", func(t *testing.T, when spec.G, it spec.S) {
const installedInNamespace = "some-namespace"
var r *require.Assertions
var observableWithInformerOption *testutil.ObservableWithInformerOption
var observableWithInitialEventOption *testutil.ObservableWithInitialEventOption
var secretsInformerFilter controller.Filter
it.Before(func() {
r = require.New(t)
observableWithInformerOption = testutil.NewObservableWithInformerOption()
observableWithInitialEventOption = testutil.NewObservableWithInitialEventOption()
secretsInformer := kubeinformers.NewSharedInformerFactory(nil, 0).Core().V1().Secrets()
_ = NewCertsManagerController(
installedInNamespace,
nil,
nil,
secretsInformer,
observableWithInformerOption.WithInformer, // make it possible to observe the behavior of the Filters
observableWithInformerOption.WithInformer, // make it possible to observe the behavior of the Filters
observableWithInitialEventOption.WithInitialEvent, // make it possible to observe the behavior of the initial event
)
secretsInformerFilter = observableWithInformerOption.GetFilterForInformer(secretsInformer)
})
@@ -102,6 +103,15 @@ func TestManagerControllerInformerFilters(t *testing.T) {
})
})
})
when("starting up", func() {
it("asks for an initial event because the Secret may not exist yet and it needs to run anyway", func() {
r.Equal(controller.Key{
Namespace: installedInNamespace,
Name: "api-serving-cert",
}, observableWithInitialEventOption.GetInitialEventKey())
})
})
}, spec.Parallel(), spec.Report(report.Terminal{}))
}
@@ -130,6 +140,7 @@ func TestManagerControllerSync(t *testing.T) {
aggregatorAPIClient,
kubeInformers.Core().V1().Secrets(),
controller.WithInformer,
controller.WithInitialEvent,
)
// Set this at the last second to support calling subject.Name().
@@ -3,8 +3,7 @@ Copyright 2020 VMware, Inc.
SPDX-License-Identifier: Apache-2.0
*/
// Package autoregistration updates the pre-registered APIService.
package autoregistration
package apicerts
import (
"context"
@@ -3,7 +3,7 @@ Copyright 2020 VMware, Inc.
SPDX-License-Identifier: Apache-2.0
*/
package autoregistration
package apicerts
import (
"context"
+3
View File
@@ -29,3 +29,6 @@ type WithInformerOptionFunc func(
getter controller.InformerGetter,
filter controller.Filter,
opt controller.InformerOption) controller.Option
// Same signature as controller.WithInitialEvent().
type WithInitialEventOptionFunc func(key controller.Key) controller.Option
@@ -66,6 +66,7 @@ func PrepareControllers(
aggregatorClient,
installationNamespaceK8sInformers.Core().V1().Secrets(),
controller.WithInformer,
controller.WithInitialEvent,
),
singletonWorker,
).
@@ -8,23 +8,24 @@ package testutil
import "github.com/suzerain-io/controller-go"
type ObservableWithInformerOption struct {
InformerToFilterMap map[controller.InformerGetter]controller.Filter
informerToFilterMap map[controller.InformerGetter]controller.Filter
}
func NewObservableWithInformerOption() *ObservableWithInformerOption {
return &ObservableWithInformerOption{
InformerToFilterMap: make(map[controller.InformerGetter]controller.Filter),
informerToFilterMap: make(map[controller.InformerGetter]controller.Filter),
}
}
func (i *ObservableWithInformerOption) WithInformer(
getter controller.InformerGetter,
filter controller.Filter,
opt controller.InformerOption) controller.Option {
i.InformerToFilterMap[getter] = filter
opt controller.InformerOption,
) controller.Option {
i.informerToFilterMap[getter] = filter
return controller.WithInformer(getter, filter, opt)
}
func (i *ObservableWithInformerOption) GetFilterForInformer(getter controller.InformerGetter) controller.Filter {
return i.InformerToFilterMap[getter]
return i.informerToFilterMap[getter]
}
@@ -0,0 +1,25 @@
/*
Copyright 2020 VMware, Inc.
SPDX-License-Identifier: Apache-2.0
*/
package testutil
import "github.com/suzerain-io/controller-go"
type ObservableWithInitialEventOption struct {
key controller.Key
}
func NewObservableWithInitialEventOption() *ObservableWithInitialEventOption {
return &ObservableWithInitialEventOption{}
}
func (i *ObservableWithInitialEventOption) WithInitialEvent(key controller.Key) controller.Option {
i.key = key
return controller.WithInitialEvent(key)
}
func (i *ObservableWithInitialEventOption) GetInitialEventKey() controller.Key {
return i.key
}