knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/reconciler/reconcile_common_test.go (about)

     1  /*
     2  Copyright 2020 The Knative Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      https://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package reconciler
    18  
    19  import (
    20  	"context"
    21  	"testing"
    22  	"time"
    23  
    24  	corev1 "k8s.io/api/core/v1"
    25  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    26  
    27  	"knative.dev/pkg/apis"
    28  	duckv1 "knative.dev/pkg/apis/duck/v1"
    29  )
    30  
    31  type TestResource struct {
    32  	metav1.TypeMeta   `json:",inline"`
    33  	metav1.ObjectMeta `json:"metadata,omitempty"`
    34  
    35  	Status duckv1.Status `json:"status"`
    36  }
    37  
    38  func (t *TestResource) SetDefaults(context.Context) {
    39  	t.Annotations = map[string]string{"default": "was set"}
    40  }
    41  
    42  func (t *TestResource) GetStatus() *duckv1.Status {
    43  	return &t.Status
    44  }
    45  
    46  func (*TestResource) GetConditionSet() apis.ConditionSet {
    47  	return apis.NewLivingConditionSet("Foo", "Bar")
    48  }
    49  
    50  func makeResource() *TestResource {
    51  	fooCond := apis.Condition{
    52  		Type:    "Foo",
    53  		Status:  corev1.ConditionTrue,
    54  		Message: "Something something foo",
    55  	}
    56  	readyCond := apis.Condition{
    57  		Type:    apis.ConditionReady,
    58  		Status:  corev1.ConditionTrue,
    59  		Message: "Something something bar",
    60  	}
    61  
    62  	return &TestResource{
    63  		ObjectMeta: metav1.ObjectMeta{
    64  			Generation: 42,
    65  		},
    66  
    67  		Status: duckv1.Status{
    68  			ObservedGeneration: 0,
    69  			Conditions:         duckv1.Conditions{fooCond, readyCond},
    70  		},
    71  	}
    72  }
    73  
    74  func TestPreProcess(t *testing.T) {
    75  	resource := makeResource()
    76  	krShape := duckv1.KRShaped(resource)
    77  
    78  	PreProcessReconcile(context.Background(), krShape)
    79  
    80  	if resource.Annotations["default"] != "was set" {
    81  		t.Errorf("Expected default annotations set got=%v", resource.Annotations)
    82  	}
    83  
    84  	if rc := resource.Status.GetCondition("Ready"); rc.Status != "Unknown" {
    85  		t.Errorf("Expected unchanged ready status got=%s want=Unknown", rc.Status)
    86  	}
    87  
    88  	// Ensure Foo is untouched
    89  	if rc := resource.Status.GetCondition("Foo"); rc.Status != "True" {
    90  		t.Errorf("Expected dependant condition to remain got=%s want=True", rc.Status)
    91  	}
    92  
    93  	// Ensure Bar is initialized
    94  	if rc := resource.Status.GetCondition("Bar"); rc.Status != "True" {
    95  		t.Errorf("Expected conditions to be initialized got=%s want=True", rc.Status)
    96  	}
    97  }
    98  
    99  func TestPostProcessReconcileBumpsGeneration(t *testing.T) {
   100  	resource := makeResource()
   101  
   102  	krShape := duckv1.KRShaped(resource)
   103  	PostProcessReconcile(context.Background(), krShape, krShape)
   104  
   105  	if resource.Status.ObservedGeneration != resource.Generation {
   106  		t.Errorf("Expected observed generation bump got=%d want=%d",
   107  			resource.Status.ObservedGeneration, resource.Generation)
   108  	}
   109  
   110  	if krShape.GetStatus().ObservedGeneration != krShape.GetGeneration() {
   111  		t.Errorf("Expected observed generation bump got=%d want=%d",
   112  			resource.Status.ObservedGeneration, resource.Generation)
   113  	}
   114  }
   115  
   116  func TestPostProcessReconcileUpdatesTransitionTimes(t *testing.T) {
   117  	oldNow := apis.VolatileTime{Inner: metav1.NewTime(time.Now())}
   118  	resource := makeResource()
   119  	oldResource := makeResource()
   120  	// initialize old conditions with oldNow
   121  	oldResource.Status.Conditions[0].LastTransitionTime = oldNow
   122  	oldResource.Status.Conditions[1].LastTransitionTime = oldNow
   123  	// change the second condition, but keep the old timestamp.
   124  	resource.Status.Conditions[1].LastTransitionTime = oldNow
   125  	resource.Status.Conditions[1].Status = corev1.ConditionFalse
   126  
   127  	new := duckv1.KRShaped(resource)
   128  	old := duckv1.KRShaped(oldResource)
   129  	PostProcessReconcile(context.Background(), new, old)
   130  
   131  	unchangedCond := resource.Status.Conditions[0]
   132  	if unchangedCond.LastTransitionTime != oldNow {
   133  		t.Errorf("Expected unchanged condition to keep old timestamp. Got=%v Want=%v",
   134  			unchangedCond.LastTransitionTime, oldNow)
   135  	}
   136  
   137  	changedCond := resource.Status.Conditions[1]
   138  	if changedCond.LastTransitionTime == oldNow {
   139  		t.Errorf("Expected changed condition to get a new timestamp. Got=%v Want=%v",
   140  			changedCond.LastTransitionTime, oldNow)
   141  	}
   142  }