2022-09-05 03:06:08 -04:00
|
|
|
/*
|
|
|
|
Copyright (c) Edgeless Systems GmbH
|
|
|
|
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
*/
|
|
|
|
|
2022-06-29 08:48:40 -04:00
|
|
|
package controllers
|
|
|
|
|
|
|
|
import (
|
2023-05-24 12:57:45 -04:00
|
|
|
"context"
|
2022-06-29 08:48:40 -04:00
|
|
|
"errors"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
|
|
"k8s.io/apimachinery/pkg/types"
|
|
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
|
|
"sigs.k8s.io/controller-runtime/pkg/event"
|
|
|
|
"sigs.k8s.io/controller-runtime/pkg/reconcile"
|
|
|
|
|
2023-02-14 12:46:48 -05:00
|
|
|
nodemaintenancev1beta1 "github.com/edgelesssys/constellation/v2/3rdparty/node-maintenance-operator/api/v1beta1"
|
2024-01-08 07:19:38 -05:00
|
|
|
updatev1alpha1 "github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/api/v1alpha1"
|
2022-06-29 08:48:40 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestScalingGroupImageChangedPredicate(t *testing.T) {
|
|
|
|
testCases := map[string]struct {
|
|
|
|
event event.UpdateEvent
|
|
|
|
wantProcessing bool
|
|
|
|
}{
|
|
|
|
"old object is not a scaling group": {
|
|
|
|
event: event.UpdateEvent{
|
|
|
|
ObjectNew: &updatev1alpha1.ScalingGroup{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"new object is not a scaling group": {
|
|
|
|
event: event.UpdateEvent{
|
|
|
|
ObjectOld: &updatev1alpha1.ScalingGroup{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"image reference is unchanged": {
|
|
|
|
event: event.UpdateEvent{
|
|
|
|
ObjectOld: &updatev1alpha1.ScalingGroup{
|
|
|
|
Status: updatev1alpha1.ScalingGroupStatus{ImageReference: "image-reference"},
|
|
|
|
},
|
|
|
|
ObjectNew: &updatev1alpha1.ScalingGroup{
|
|
|
|
Status: updatev1alpha1.ScalingGroupStatus{ImageReference: "image-reference"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"image reference has changed": {
|
|
|
|
event: event.UpdateEvent{
|
|
|
|
ObjectOld: &updatev1alpha1.ScalingGroup{
|
|
|
|
Status: updatev1alpha1.ScalingGroupStatus{ImageReference: "old-image-reference"},
|
|
|
|
},
|
|
|
|
ObjectNew: &updatev1alpha1.ScalingGroup{
|
|
|
|
Status: updatev1alpha1.ScalingGroupStatus{ImageReference: "new-image-reference"},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
wantProcessing: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
predicate := scalingGroupImageChangedPredicate()
|
|
|
|
assert.Equal(tc.wantProcessing, predicate.Update(tc.event))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAutoscalerEnabledStatusChangedPredicate(t *testing.T) {
|
|
|
|
testCases := map[string]struct {
|
|
|
|
event event.UpdateEvent
|
|
|
|
wantProcessing bool
|
|
|
|
}{
|
|
|
|
"old object is not an autoscaling strategy": {
|
|
|
|
event: event.UpdateEvent{
|
|
|
|
ObjectNew: &updatev1alpha1.AutoscalingStrategy{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"new object is not an autoscaling strategy": {
|
|
|
|
event: event.UpdateEvent{
|
|
|
|
ObjectOld: &updatev1alpha1.AutoscalingStrategy{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"status is unchanged": {
|
|
|
|
event: event.UpdateEvent{
|
|
|
|
ObjectOld: &updatev1alpha1.AutoscalingStrategy{
|
|
|
|
Status: updatev1alpha1.AutoscalingStrategyStatus{Enabled: true},
|
|
|
|
},
|
|
|
|
ObjectNew: &updatev1alpha1.AutoscalingStrategy{
|
|
|
|
Status: updatev1alpha1.AutoscalingStrategyStatus{Enabled: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"status has changed": {
|
|
|
|
event: event.UpdateEvent{
|
|
|
|
ObjectOld: &updatev1alpha1.AutoscalingStrategy{
|
|
|
|
Status: updatev1alpha1.AutoscalingStrategyStatus{},
|
|
|
|
},
|
|
|
|
ObjectNew: &updatev1alpha1.AutoscalingStrategy{
|
|
|
|
Status: updatev1alpha1.AutoscalingStrategyStatus{Enabled: true},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
wantProcessing: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
predicate := autoscalerEnabledStatusChangedPredicate()
|
|
|
|
assert.Equal(tc.wantProcessing, predicate.Update(tc.event))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNodeReadyPredicate(t *testing.T) {
|
|
|
|
testCases := map[string]struct {
|
|
|
|
event event.UpdateEvent
|
|
|
|
wantProcessing bool
|
|
|
|
}{
|
|
|
|
"old object is not a node": {
|
|
|
|
event: event.UpdateEvent{
|
|
|
|
ObjectNew: &corev1.Node{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"new object is not a node": {
|
|
|
|
event: event.UpdateEvent{
|
|
|
|
ObjectOld: &corev1.Node{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"status is unchanged": {
|
|
|
|
event: event.UpdateEvent{
|
|
|
|
ObjectOld: &corev1.Node{},
|
|
|
|
ObjectNew: &corev1.Node{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"node became ready": {
|
|
|
|
event: event.UpdateEvent{
|
|
|
|
ObjectOld: &corev1.Node{
|
|
|
|
Status: corev1.NodeStatus{
|
|
|
|
Conditions: []corev1.NodeCondition{
|
|
|
|
{Type: corev1.NodeReady, Status: corev1.ConditionFalse},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ObjectNew: &corev1.Node{
|
|
|
|
Status: corev1.NodeStatus{
|
|
|
|
Conditions: []corev1.NodeCondition{
|
|
|
|
{Type: corev1.NodeReady, Status: corev1.ConditionTrue},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
wantProcessing: true,
|
|
|
|
},
|
|
|
|
"node acquired provider id": {
|
|
|
|
event: event.UpdateEvent{
|
|
|
|
ObjectOld: &corev1.Node{},
|
|
|
|
ObjectNew: &corev1.Node{
|
|
|
|
Spec: corev1.NodeSpec{
|
|
|
|
ProviderID: "provider-id",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
wantProcessing: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
predicate := nodeReadyPredicate()
|
|
|
|
assert.Equal(tc.wantProcessing, predicate.Update(tc.event))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNodeMaintenanceSucceededPredicate(t *testing.T) {
|
|
|
|
testCases := map[string]struct {
|
|
|
|
event event.UpdateEvent
|
|
|
|
wantProcessing bool
|
|
|
|
}{
|
|
|
|
"old object is not a node maintenance resource": {
|
|
|
|
event: event.UpdateEvent{
|
|
|
|
ObjectNew: &nodemaintenancev1beta1.NodeMaintenance{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"new object is not a node maintenance resource": {
|
|
|
|
event: event.UpdateEvent{
|
|
|
|
ObjectOld: &nodemaintenancev1beta1.NodeMaintenance{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"status is unchanged": {
|
|
|
|
event: event.UpdateEvent{
|
|
|
|
ObjectOld: &nodemaintenancev1beta1.NodeMaintenance{
|
|
|
|
Status: nodemaintenancev1beta1.NodeMaintenanceStatus{
|
|
|
|
Phase: nodemaintenancev1beta1.MaintenanceRunning,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ObjectNew: &nodemaintenancev1beta1.NodeMaintenance{
|
|
|
|
Status: nodemaintenancev1beta1.NodeMaintenanceStatus{
|
|
|
|
Phase: nodemaintenancev1beta1.MaintenanceRunning,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"status has changed": {
|
|
|
|
event: event.UpdateEvent{
|
|
|
|
ObjectOld: &nodemaintenancev1beta1.NodeMaintenance{
|
|
|
|
Status: nodemaintenancev1beta1.NodeMaintenanceStatus{
|
|
|
|
Phase: nodemaintenancev1beta1.MaintenanceRunning,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
ObjectNew: &nodemaintenancev1beta1.NodeMaintenance{
|
|
|
|
Status: nodemaintenancev1beta1.NodeMaintenanceStatus{
|
|
|
|
Phase: nodemaintenancev1beta1.MaintenanceSucceeded,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
wantProcessing: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
predicate := nodeMaintenanceSucceededPredicate()
|
|
|
|
assert.Equal(tc.wantProcessing, predicate.Update(tc.event))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestFindObjectsForScalingGroup(t *testing.T) {
|
|
|
|
scalingGroup := updatev1alpha1.ScalingGroup{
|
|
|
|
Spec: updatev1alpha1.ScalingGroupSpec{
|
2023-01-03 06:09:53 -05:00
|
|
|
NodeVersion: "nodeversion",
|
2022-06-29 08:48:40 -04:00
|
|
|
},
|
|
|
|
}
|
|
|
|
wantRequests := []reconcile.Request{
|
|
|
|
{
|
|
|
|
NamespacedName: types.NamespacedName{
|
2023-01-03 06:09:53 -05:00
|
|
|
Name: "nodeversion",
|
2022-06-29 08:48:40 -04:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
assert := assert.New(t)
|
2023-01-03 06:09:53 -05:00
|
|
|
reconciler := NodeVersionReconciler{}
|
2023-05-24 12:57:45 -04:00
|
|
|
requests := reconciler.findObjectsForScalingGroup(context.TODO(), &scalingGroup)
|
2022-06-29 08:48:40 -04:00
|
|
|
assert.ElementsMatch(wantRequests, requests)
|
|
|
|
}
|
|
|
|
|
2023-01-03 06:09:53 -05:00
|
|
|
func TestFindAllNodeVersions(t *testing.T) {
|
2022-06-29 08:48:40 -04:00
|
|
|
testCases := map[string]struct {
|
2023-01-03 06:09:53 -05:00
|
|
|
nodeVersion client.Object
|
|
|
|
listNodeVersionsErr error
|
|
|
|
wantRequests []reconcile.Request
|
2022-06-29 08:48:40 -04:00
|
|
|
}{
|
|
|
|
"getting the corresponding node images fails": {
|
2023-01-03 06:09:53 -05:00
|
|
|
listNodeVersionsErr: errors.New("get-node-version-err"),
|
2022-06-29 08:48:40 -04:00
|
|
|
},
|
|
|
|
"node image reconcile request is returned": {
|
2023-01-03 06:09:53 -05:00
|
|
|
nodeVersion: &updatev1alpha1.NodeVersion{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "nodeversion"},
|
2022-06-29 08:48:40 -04:00
|
|
|
},
|
|
|
|
wantRequests: []reconcile.Request{
|
|
|
|
{
|
|
|
|
NamespacedName: types.NamespacedName{
|
2023-01-03 06:09:53 -05:00
|
|
|
Name: "nodeversion",
|
2022-06-29 08:48:40 -04:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, tc := range testCases {
|
|
|
|
t.Run(name, func(t *testing.T) {
|
|
|
|
assert := assert.New(t)
|
|
|
|
|
2023-01-03 06:09:53 -05:00
|
|
|
reconciler := NodeVersionReconciler{
|
|
|
|
Client: newStubReaderClient(t, []runtime.Object{tc.nodeVersion}, nil, tc.listNodeVersionsErr),
|
2022-06-29 08:48:40 -04:00
|
|
|
}
|
2023-05-24 12:57:45 -04:00
|
|
|
requests := reconciler.findAllNodeVersions(context.TODO(), nil)
|
2022-06-29 08:48:40 -04:00
|
|
|
assert.ElementsMatch(tc.wantRequests, requests)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|