mirror of https://github.com/fluxcd/cli-utils.git
add test cases for applier
This commit is contained in:
parent
d3e1ad2460
commit
5aad5ee380
|
|
@ -10,6 +10,7 @@ import (
|
|||
"io/ioutil"
|
||||
"net/http"
|
||||
"path"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
|
|
@ -23,7 +24,9 @@ import (
|
|||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/cli-runtime/pkg/resource"
|
||||
dynamicfake "k8s.io/client-go/dynamic/fake"
|
||||
"k8s.io/client-go/rest/fake"
|
||||
clienttesting "k8s.io/client-go/testing"
|
||||
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
|
||||
"k8s.io/kubectl/pkg/scheme"
|
||||
"sigs.k8s.io/cli-utils/pkg/apply/event"
|
||||
|
|
@ -66,6 +69,34 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
var deploymentUnmatched = &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "foo",
|
||||
"namespace": "default",
|
||||
"annotations": map[string]interface{}{
|
||||
"config.k8s.io/owning-inventory": "unmatched",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var deploymentMatched = &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": "apps/v1",
|
||||
"kind": "Deployment",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "foo",
|
||||
"namespace": "default",
|
||||
"annotations": map[string]interface{}{
|
||||
"config.k8s.io/owning-inventory": "test",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// resourceStatus contains information about a specific resource, such
|
||||
// as the manifest yaml and the URL path for this resource in the
|
||||
// client. It also contains a factory function for creating a new
|
||||
|
|
@ -83,6 +114,9 @@ type expectedEvent struct {
|
|||
statusEventType event.StatusEventType
|
||||
pruneEventType event.PruneEventType
|
||||
deleteEventType event.DeleteEventType
|
||||
|
||||
applyErrorType error
|
||||
pruneEventOp event.PruneEventOperation
|
||||
}
|
||||
|
||||
func TestApplier(t *testing.T) {
|
||||
|
|
@ -94,6 +128,7 @@ func TestApplier(t *testing.T) {
|
|||
prune bool
|
||||
statusEvents []pollevent.Event
|
||||
expectedEventTypes []expectedEvent
|
||||
clusterObj *unstructured.Unstructured
|
||||
}{
|
||||
"apply without status or prune": {
|
||||
namespace: "default",
|
||||
|
|
@ -158,14 +193,14 @@ func TestApplier(t *testing.T) {
|
|||
{
|
||||
EventType: pollevent.ResourceUpdateEvent,
|
||||
Resource: &pollevent.ResourceStatus{
|
||||
Identifier: toIdentifier(t, resources["deployment"], "default"),
|
||||
Identifier: toIdentifier(t, resources["deployment"]),
|
||||
Status: status.InProgressStatus,
|
||||
},
|
||||
},
|
||||
{
|
||||
EventType: pollevent.ResourceUpdateEvent,
|
||||
Resource: &pollevent.ResourceStatus{
|
||||
Identifier: toIdentifier(t, resources["deployment"], "default"),
|
||||
Identifier: toIdentifier(t, resources["deployment"]),
|
||||
Status: status.CurrentStatus,
|
||||
},
|
||||
},
|
||||
|
|
@ -200,6 +235,152 @@ func TestApplier(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
"apply with inventory object and cluster object": {
|
||||
namespace: "default",
|
||||
resources: []resourceInfo{
|
||||
resources["deployment"],
|
||||
resources["inventoryObject"],
|
||||
},
|
||||
handlers: []handler{
|
||||
&nsHandler{},
|
||||
&inventoryObjectHandler{},
|
||||
&genericHandler{
|
||||
resourceInfo: resources["deployment"],
|
||||
namespace: "default",
|
||||
},
|
||||
},
|
||||
reconcileTimeout: time.Minute,
|
||||
statusEvents: []pollevent.Event{
|
||||
{
|
||||
EventType: pollevent.ResourceUpdateEvent,
|
||||
Resource: &pollevent.ResourceStatus{
|
||||
Identifier: object.ObjMetadata{
|
||||
Name: "foo-dcf2c498",
|
||||
Namespace: "default",
|
||||
GroupKind: schema.GroupKind{
|
||||
Group: "",
|
||||
Kind: "ConfigMap",
|
||||
},
|
||||
},
|
||||
Status: status.CurrentStatus,
|
||||
},
|
||||
},
|
||||
{
|
||||
EventType: pollevent.ResourceUpdateEvent,
|
||||
Resource: &pollevent.ResourceStatus{
|
||||
Identifier: toIdentifier(t, resources["deployment"]),
|
||||
Status: status.InProgressStatus,
|
||||
},
|
||||
},
|
||||
{
|
||||
EventType: pollevent.ResourceUpdateEvent,
|
||||
Resource: &pollevent.ResourceStatus{
|
||||
Identifier: toIdentifier(t, resources["deployment"]),
|
||||
Status: status.CurrentStatus,
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedEventTypes: []expectedEvent{
|
||||
{
|
||||
eventType: event.InitType,
|
||||
},
|
||||
{
|
||||
eventType: event.ApplyType,
|
||||
applyEventType: event.ApplyEventResourceUpdate,
|
||||
applyErrorType: inventory.NewInventoryOverlapError(fmt.Errorf("")),
|
||||
},
|
||||
{
|
||||
eventType: event.ApplyType,
|
||||
applyEventType: event.ApplyEventCompleted,
|
||||
},
|
||||
{
|
||||
eventType: event.StatusType,
|
||||
statusEventType: event.StatusEventResourceUpdate,
|
||||
},
|
||||
{
|
||||
eventType: event.StatusType,
|
||||
statusEventType: event.StatusEventResourceUpdate,
|
||||
},
|
||||
{
|
||||
eventType: event.StatusType,
|
||||
statusEventType: event.StatusEventResourceUpdate,
|
||||
},
|
||||
{
|
||||
eventType: event.StatusType,
|
||||
statusEventType: event.StatusEventCompleted,
|
||||
},
|
||||
},
|
||||
clusterObj: deploymentUnmatched,
|
||||
},
|
||||
"prune with inventory object annotation unmatched": {
|
||||
namespace: "default",
|
||||
resources: []resourceInfo{
|
||||
resources["inventoryObject"],
|
||||
},
|
||||
handlers: []handler{
|
||||
&nsHandler{},
|
||||
&inventoryObjectHandler{},
|
||||
&genericHandler{
|
||||
namespace: "default",
|
||||
},
|
||||
},
|
||||
reconcileTimeout: 0,
|
||||
expectedEventTypes: []expectedEvent{
|
||||
{
|
||||
eventType: event.InitType,
|
||||
},
|
||||
{
|
||||
eventType: event.ApplyType,
|
||||
applyEventType: event.ApplyEventCompleted,
|
||||
},
|
||||
{
|
||||
eventType: event.PruneType,
|
||||
pruneEventType: event.PruneEventResourceUpdate,
|
||||
pruneEventOp: event.PruneSkipped,
|
||||
},
|
||||
{
|
||||
eventType: event.PruneType,
|
||||
pruneEventType: event.PruneEventCompleted,
|
||||
},
|
||||
},
|
||||
clusterObj: deploymentUnmatched,
|
||||
prune: true,
|
||||
},
|
||||
"prune with inventory object annotation matched": {
|
||||
namespace: "default",
|
||||
resources: []resourceInfo{
|
||||
resources["inventoryObject"],
|
||||
},
|
||||
handlers: []handler{
|
||||
&nsHandler{},
|
||||
&inventoryObjectHandler{},
|
||||
&genericHandler{
|
||||
resourceInfo: resources["deployment"],
|
||||
namespace: "default",
|
||||
},
|
||||
},
|
||||
reconcileTimeout: 0,
|
||||
expectedEventTypes: []expectedEvent{
|
||||
{
|
||||
eventType: event.InitType,
|
||||
},
|
||||
{
|
||||
eventType: event.ApplyType,
|
||||
applyEventType: event.ApplyEventCompleted,
|
||||
},
|
||||
{
|
||||
eventType: event.PruneType,
|
||||
pruneEventType: event.PruneEventResourceUpdate,
|
||||
pruneEventOp: event.Pruned,
|
||||
},
|
||||
{
|
||||
eventType: event.PruneType,
|
||||
pruneEventType: event.PruneEventCompleted,
|
||||
},
|
||||
},
|
||||
clusterObj: deploymentMatched,
|
||||
prune: true,
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range testCases {
|
||||
|
|
@ -211,6 +392,9 @@ func TestApplier(t *testing.T) {
|
|||
defer tf.Cleanup()
|
||||
|
||||
tf.UnstructuredClient = newFakeRESTClient(t, tc.handlers)
|
||||
if tc.clusterObj != nil {
|
||||
tf.FakeDynamicClient = fakeDynamicClient(tc.clusterObj)
|
||||
}
|
||||
|
||||
cf := provider.NewProvider(tf)
|
||||
applier := NewApplier(cf)
|
||||
|
|
@ -222,7 +406,17 @@ func TestApplier(t *testing.T) {
|
|||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
applier.invClient = inventory.NewFakeInventoryClient([]object.ObjMetadata{})
|
||||
|
||||
objmeta := []object.ObjMetadata{}
|
||||
if tc.clusterObj != nil {
|
||||
objmeta = append(objmeta, object.UnstructuredToObjMeta(tc.clusterObj))
|
||||
}
|
||||
invClient := inventory.NewFakeInventoryClient(objmeta)
|
||||
applier.invClient = invClient
|
||||
err = applier.PruneOptions.Initialize(cf.Factory(), invClient)
|
||||
if !assert.NoError(t, err) {
|
||||
return
|
||||
}
|
||||
|
||||
poller := &fakePoller{
|
||||
events: tc.statusEvents,
|
||||
|
|
@ -255,10 +449,12 @@ func TestApplier(t *testing.T) {
|
|||
case event.InitType:
|
||||
case event.ApplyType:
|
||||
assert.Equal(t, expected.applyEventType.String(), e.ApplyEvent.Type.String())
|
||||
assert.Equal(t, reflect.TypeOf(expected.applyErrorType), reflect.TypeOf(e.ApplyEvent.Error))
|
||||
case event.StatusType:
|
||||
assert.Equal(t, expected.statusEventType.String(), e.StatusEvent.Type.String())
|
||||
case event.PruneType:
|
||||
assert.Equal(t, expected.pruneEventType.String(), e.PruneEvent.Type.String())
|
||||
assert.Equal(t, expected.pruneEventOp.String(), e.PruneEvent.Operation.String())
|
||||
case event.DeleteType:
|
||||
assert.Equal(t, expected.deleteEventType.String(), e.DeleteEvent.Type.String())
|
||||
default:
|
||||
|
|
@ -523,7 +719,7 @@ func newFakeRESTClient(t *testing.T, handlers []handler) *fake.RESTClient {
|
|||
}
|
||||
}
|
||||
|
||||
func toIdentifier(t *testing.T, resourceInfo resourceInfo, namespace string) object.ObjMetadata {
|
||||
func toIdentifier(t *testing.T, resourceInfo resourceInfo) object.ObjMetadata {
|
||||
obj := resourceInfo.factoryFunc()
|
||||
err := runtime.DecodeInto(codec, []byte(resourceInfo.manifest), obj)
|
||||
if err != nil {
|
||||
|
|
@ -537,7 +733,7 @@ func toIdentifier(t *testing.T, resourceInfo resourceInfo, namespace string) obj
|
|||
return object.ObjMetadata{
|
||||
GroupKind: obj.GetObjectKind().GroupVersionKind().GroupKind(),
|
||||
Name: accessor.GetName(),
|
||||
Namespace: namespace,
|
||||
Namespace: "default",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -768,3 +964,17 @@ func objSetsEqual(setA []*unstructured.Unstructured, setB []*unstructured.Unstru
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// fakeDynamicClient returns a fake dynamic client.
|
||||
func fakeDynamicClient(obj *unstructured.Unstructured) *dynamicfake.FakeDynamicClient {
|
||||
fakeClient := dynamicfake.NewSimpleDynamicClient(runtime.NewScheme())
|
||||
|
||||
fakeClient.PrependReactor("get", "deployments", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
return true, obj, nil
|
||||
})
|
||||
fakeClient.PrependReactor("delete", "deployments", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
|
||||
return true, nil, nil
|
||||
})
|
||||
|
||||
return fakeClient
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue