mirror of https://github.com/knative/caching.git
148 lines
4.8 KiB
Go
148 lines
4.8 KiB
Go
/*
|
|
Copyright 2019 The Knative 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 testing
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
fakeapixclient "knative.dev/pkg/client/injection/apiextensions/client/fake"
|
|
fakekubeclient "knative.dev/pkg/client/injection/kube/client/fake"
|
|
fakedynamicclient "knative.dev/pkg/injection/clients/dynamicclient/fake"
|
|
|
|
"knative.dev/pkg/configmap"
|
|
"knative.dev/pkg/controller"
|
|
"knative.dev/pkg/logging"
|
|
logtesting "knative.dev/pkg/logging/testing"
|
|
|
|
"k8s.io/apimachinery/pkg/api/meta"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
ktesting "k8s.io/client-go/testing"
|
|
"k8s.io/client-go/tools/record"
|
|
|
|
rtesting "knative.dev/pkg/reconciler/testing"
|
|
)
|
|
|
|
const (
|
|
// maxEventBufferSize is the estimated max number of event notifications that
|
|
// can be buffered during reconciliation.
|
|
maxEventBufferSize = 10
|
|
)
|
|
|
|
// Ctor functions create a k8s controller with given params.
|
|
type Ctor func(context.Context, *Listers, configmap.Watcher) controller.Reconciler
|
|
|
|
// MakeFactory creates a reconciler factory with fake clients and controller created by `ctor`.
|
|
func MakeFactory(ctor Ctor) rtesting.Factory {
|
|
return func(t *testing.T, r *rtesting.TableRow) (
|
|
controller.Reconciler, rtesting.ActionRecorderList, rtesting.EventList, *rtesting.FakeStatsReporter) {
|
|
ls := NewListers(r.Objects)
|
|
|
|
ctx := r.Ctx
|
|
if ctx == nil {
|
|
ctx = context.Background()
|
|
}
|
|
logger := logtesting.TestLogger(t)
|
|
ctx = logging.WithLogger(ctx, logger)
|
|
|
|
ctx, kubeClient := fakekubeclient.With(ctx, ls.GetKubeObjects()...)
|
|
ctx, apixClient := fakeapixclient.With(ctx, ls.GetApiExtensionsObjects()...)
|
|
ctx, dynamicClient := fakedynamicclient.With(ctx,
|
|
ls.NewScheme(), ToUnstructured(t, ls.NewScheme(), r.Objects)...)
|
|
|
|
// The dynamic client's support for patching is BS. Implement it
|
|
// here via PrependReactor (this can be overridden below by the
|
|
// provided reactors).
|
|
dynamicClient.PrependReactor("patch", "*",
|
|
func(action ktesting.Action) (bool, runtime.Object, error) {
|
|
return true, nil, nil
|
|
})
|
|
|
|
eventRecorder := record.NewFakeRecorder(maxEventBufferSize)
|
|
ctx = controller.WithEventRecorder(ctx, eventRecorder)
|
|
statsReporter := &rtesting.FakeStatsReporter{}
|
|
|
|
// This is needed for the tests that use generated names and
|
|
// the object cannot be created beforehand.
|
|
kubeClient.PrependReactor("create", "*",
|
|
func(action ktesting.Action) (bool, runtime.Object, error) {
|
|
ca := action.(ktesting.CreateAction)
|
|
ls.IndexerFor(ca.GetObject()).Add(ca.GetObject())
|
|
return false, nil, nil
|
|
},
|
|
)
|
|
apixClient.PrependReactor("create", "*",
|
|
func(action ktesting.Action) (bool, runtime.Object, error) {
|
|
ca := action.(ktesting.CreateAction)
|
|
ls.IndexerFor(ca.GetObject()).Add(ca.GetObject())
|
|
return false, nil, nil
|
|
},
|
|
)
|
|
|
|
// Set up our Controller from the fakes.
|
|
c := ctor(ctx, &ls, configmap.NewStaticWatcher())
|
|
// Update the context with the stuff we decorated it with.
|
|
r.Ctx = ctx
|
|
|
|
for _, reactor := range r.WithReactors {
|
|
kubeClient.PrependReactor("*", "*", reactor)
|
|
apixClient.PrependReactor("*", "*", reactor)
|
|
dynamicClient.PrependReactor("*", "*", reactor)
|
|
}
|
|
|
|
actionRecorderList := rtesting.ActionRecorderList{dynamicClient, kubeClient, apixClient}
|
|
eventList := rtesting.EventList{Recorder: eventRecorder}
|
|
|
|
return c, actionRecorderList, eventList, statsReporter
|
|
}
|
|
}
|
|
|
|
// ToUnstructured takes a list of k8s resources and converts them to
|
|
// Unstructured objects.
|
|
// We must pass objects as Unstructured to the dynamic client fake, or it
|
|
// won't handle them properly.
|
|
func ToUnstructured(t *testing.T, sch *runtime.Scheme, objs []runtime.Object) (us []runtime.Object) {
|
|
for _, obj := range objs {
|
|
obj = obj.DeepCopyObject() // Don't mess with the primary copy
|
|
// Determine and set the TypeMeta for this object based on our test scheme.
|
|
gvks, _, err := sch.ObjectKinds(obj)
|
|
if err != nil {
|
|
t.Fatalf("Unable to determine kind for type: %v", err)
|
|
}
|
|
apiv, k := gvks[0].ToAPIVersionAndKind()
|
|
ta, err := meta.TypeAccessor(obj)
|
|
if err != nil {
|
|
t.Fatalf("Unable to create type accessor: %v", err)
|
|
}
|
|
ta.SetAPIVersion(apiv)
|
|
ta.SetKind(k)
|
|
|
|
b, err := json.Marshal(obj)
|
|
if err != nil {
|
|
t.Fatalf("Unable to marshal: %v", err)
|
|
}
|
|
u := &unstructured.Unstructured{}
|
|
if err := json.Unmarshal(b, u); err != nil {
|
|
t.Fatalf("Unable to unmarshal: %v", err)
|
|
}
|
|
us = append(us, u)
|
|
}
|
|
return
|
|
}
|