istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pilot/pkg/model/kstatus/helper_test.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package kstatus
    16  
    17  import (
    18  	"reflect"
    19  	"testing"
    20  	"time"
    21  
    22  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    23  	k8s "sigs.k8s.io/gateway-api/apis/v1beta1"
    24  )
    25  
    26  func TestUpdateConditionIfChanged(t *testing.T) {
    27  	original := metav1.Condition{
    28  		Type:               string(k8s.RouteConditionResolvedRefs),
    29  		Reason:             string(k8s.RouteReasonResolvedRefs),
    30  		Status:             StatusTrue,
    31  		Message:            "All references resolved",
    32  		LastTransitionTime: metav1.Now(),
    33  	}
    34  	transitionTime := metav1.NewTime(original.LastTransitionTime.Add(1 * time.Second))
    35  	statusChanged := metav1.Condition{
    36  		Type:               string(k8s.RouteConditionResolvedRefs),
    37  		Reason:             string(k8s.RouteReasonResolvedRefs),
    38  		Status:             StatusFalse,
    39  		Message:            "invalid backend",
    40  		LastTransitionTime: transitionTime,
    41  	}
    42  	messageChanged := metav1.Condition{
    43  		Type:               string(k8s.RouteConditionResolvedRefs),
    44  		Reason:             string(k8s.RouteReasonResolvedRefs),
    45  		Status:             StatusTrue,
    46  		Message:            "foo",
    47  		LastTransitionTime: transitionTime,
    48  	}
    49  	anotherType := metav1.Condition{
    50  		Type:               string(k8s.RouteConditionAccepted),
    51  		Reason:             string(k8s.RouteReasonAccepted),
    52  		Status:             StatusTrue,
    53  		Message:            "Route was valid",
    54  		LastTransitionTime: transitionTime,
    55  	}
    56  
    57  	tests := []struct {
    58  		name       string
    59  		conditions []metav1.Condition
    60  		condition  metav1.Condition
    61  		want       []metav1.Condition
    62  	}{
    63  		{
    64  			name:       "unchanged",
    65  			conditions: []metav1.Condition{original},
    66  			condition: func() metav1.Condition {
    67  				c := original
    68  				c.LastTransitionTime = transitionTime
    69  				return c
    70  			}(),
    71  			want: []metav1.Condition{original},
    72  		},
    73  		{
    74  			name:       "status changed",
    75  			conditions: []metav1.Condition{original},
    76  			condition:  statusChanged,
    77  			want:       []metav1.Condition{statusChanged},
    78  		},
    79  		{
    80  			name:       "message changed",
    81  			conditions: []metav1.Condition{original},
    82  			condition:  messageChanged,
    83  			want: []metav1.Condition{func() metav1.Condition {
    84  				c := messageChanged
    85  				c.LastTransitionTime = original.LastTransitionTime
    86  				return c
    87  			}()},
    88  		},
    89  		{
    90  			name:       "another type",
    91  			conditions: []metav1.Condition{original},
    92  			condition:  anotherType,
    93  			want:       []metav1.Condition{original, anotherType},
    94  		},
    95  	}
    96  	for _, tt := range tests {
    97  		t.Run(tt.name, func(t *testing.T) {
    98  			if got := UpdateConditionIfChanged(tt.conditions, tt.condition); !reflect.DeepEqual(got, tt.want) {
    99  				t.Errorf("UpdateConditionIfChanged got %v, want %v", got, tt.want)
   100  			}
   101  		})
   102  	}
   103  }
   104  
   105  func TestGetCondition(t *testing.T) {
   106  	transitionTime := metav1.Now()
   107  
   108  	tests := []struct {
   109  		name       string
   110  		conditions []metav1.Condition
   111  		condition  string
   112  		want       metav1.Condition
   113  	}{
   114  		{
   115  			name: "ResolvedRefs condition",
   116  			conditions: []metav1.Condition{
   117  				{
   118  					Type:               string(k8s.RouteConditionAccepted),
   119  					Reason:             string(k8s.RouteReasonAccepted),
   120  					Status:             StatusFalse,
   121  					Message:            "invalid backend",
   122  					LastTransitionTime: transitionTime,
   123  				},
   124  				{
   125  					Type:               string(k8s.RouteConditionResolvedRefs),
   126  					Reason:             string(k8s.RouteReasonResolvedRefs),
   127  					Status:             StatusTrue,
   128  					Message:            "foo",
   129  					LastTransitionTime: transitionTime,
   130  				},
   131  			},
   132  			condition: string(k8s.RouteConditionResolvedRefs),
   133  			want: metav1.Condition{
   134  				Type:               string(k8s.RouteConditionResolvedRefs),
   135  				Reason:             string(k8s.RouteReasonResolvedRefs),
   136  				Status:             StatusTrue,
   137  				Message:            "foo",
   138  				LastTransitionTime: transitionTime,
   139  			},
   140  		},
   141  		{
   142  			name: "Empty condition",
   143  			conditions: []metav1.Condition{
   144  				{
   145  					Type:               string(k8s.RouteConditionAccepted),
   146  					Reason:             string(k8s.RouteReasonAccepted),
   147  					Status:             StatusFalse,
   148  					Message:            "invalid backend",
   149  					LastTransitionTime: transitionTime,
   150  				},
   151  			},
   152  			condition: "",
   153  			want:      metav1.Condition{},
   154  		},
   155  	}
   156  	for _, tt := range tests {
   157  		t.Run(tt.name, func(t *testing.T) {
   158  			if got := GetCondition(tt.conditions, tt.condition); !reflect.DeepEqual(got, tt.want) {
   159  				t.Errorf("GetCondition got %v, want %v", got, tt.want)
   160  			}
   161  		})
   162  	}
   163  }
   164  
   165  func TestCreateCondition(t *testing.T) {
   166  	transitionTime := metav1.Now()
   167  	tests := []struct {
   168  		name        string
   169  		conditions  []metav1.Condition
   170  		condition   metav1.Condition
   171  		unsetReason string
   172  		want        []metav1.Condition
   173  	}{
   174  		{
   175  			name: "condition is set, reason is unsetReason",
   176  			conditions: []metav1.Condition{
   177  				{
   178  					Type:               string(k8s.RouteConditionAccepted),
   179  					Reason:             string(k8s.RouteReasonAccepted),
   180  					Status:             StatusFalse,
   181  					Message:            "invalid backend",
   182  					LastTransitionTime: transitionTime,
   183  				},
   184  			},
   185  			condition: metav1.Condition{
   186  				Type:               string(k8s.RouteConditionAccepted),
   187  				Reason:             string(k8s.RouteReasonAccepted),
   188  				Status:             StatusTrue,
   189  				Message:            "foo",
   190  				LastTransitionTime: transitionTime,
   191  			},
   192  			unsetReason: string(k8s.RouteReasonAccepted),
   193  			want: []metav1.Condition{
   194  				{
   195  					Type:               string(k8s.RouteConditionAccepted),
   196  					Reason:             string(k8s.RouteReasonAccepted),
   197  					Status:             StatusTrue,
   198  					Message:            "foo",
   199  					LastTransitionTime: transitionTime,
   200  				},
   201  			},
   202  		},
   203  		{
   204  			name: "condition is set, reason is not unsetReason",
   205  			conditions: []metav1.Condition{
   206  				{
   207  					Type:               string(k8s.RouteConditionAccepted),
   208  					Reason:             string(k8s.RouteReasonAccepted),
   209  					Status:             StatusFalse,
   210  					Message:            "invalid backend",
   211  					LastTransitionTime: transitionTime,
   212  				},
   213  			},
   214  			condition: metav1.Condition{
   215  				Type:               string(k8s.RouteConditionAccepted),
   216  				Reason:             string(k8s.RouteReasonAccepted),
   217  				Status:             StatusTrue,
   218  				Message:            "foo",
   219  				LastTransitionTime: transitionTime,
   220  			},
   221  			unsetReason: string(k8s.RouteReasonPending),
   222  			want: []metav1.Condition{
   223  				{
   224  					Type:               string(k8s.RouteConditionAccepted),
   225  					Reason:             string(k8s.RouteReasonAccepted),
   226  					Status:             StatusFalse,
   227  					Message:            "invalid backend",
   228  					LastTransitionTime: transitionTime,
   229  				},
   230  			},
   231  		},
   232  		{
   233  			name: "add a new condition",
   234  			conditions: []metav1.Condition{
   235  				{
   236  					Type:               string(k8s.RouteConditionAccepted),
   237  					Reason:             string(k8s.RouteReasonAccepted),
   238  					Status:             StatusFalse,
   239  					Message:            "invalid backend",
   240  					LastTransitionTime: transitionTime,
   241  				},
   242  			},
   243  			condition: metav1.Condition{
   244  				Type:               string(k8s.RouteConditionResolvedRefs),
   245  				Reason:             string(k8s.RouteReasonResolvedRefs),
   246  				Status:             StatusTrue,
   247  				Message:            "foo",
   248  				LastTransitionTime: transitionTime,
   249  			},
   250  			unsetReason: string(k8s.RouteReasonNotAllowedByListeners),
   251  			want: []metav1.Condition{
   252  				{
   253  					Type:               string(k8s.RouteConditionAccepted),
   254  					Reason:             string(k8s.RouteConditionAccepted),
   255  					Status:             StatusFalse,
   256  					Message:            "invalid backend",
   257  					LastTransitionTime: transitionTime,
   258  				},
   259  				{
   260  					Type:               string(k8s.RouteConditionResolvedRefs),
   261  					Reason:             string(k8s.RouteReasonResolvedRefs),
   262  					Status:             StatusTrue,
   263  					Message:            "foo",
   264  					LastTransitionTime: transitionTime,
   265  				},
   266  			},
   267  		},
   268  	}
   269  	for _, tt := range tests {
   270  		t.Run(tt.name, func(t *testing.T) {
   271  			if got := CreateCondition(tt.conditions, tt.condition, tt.unsetReason); !reflect.DeepEqual(got, tt.want) {
   272  				t.Errorf("CreateCondition got %v, want %v", got, tt.want)
   273  			}
   274  		})
   275  	}
   276  }
   277  
   278  func TestInvertStatus(t *testing.T) {
   279  	tests := []struct {
   280  		name   string
   281  		status metav1.ConditionStatus
   282  		want   metav1.ConditionStatus
   283  	}{
   284  		{
   285  			name:   "return false",
   286  			status: metav1.ConditionTrue,
   287  			want:   metav1.ConditionFalse,
   288  		},
   289  		{
   290  			name:   "return true",
   291  			status: metav1.ConditionFalse,
   292  			want:   metav1.ConditionTrue,
   293  		},
   294  		{
   295  			name:   "default return false",
   296  			status: metav1.ConditionUnknown,
   297  			want:   metav1.ConditionFalse,
   298  		},
   299  	}
   300  	for _, tt := range tests {
   301  		t.Run(tt.name, func(t *testing.T) {
   302  			if got := InvertStatus(tt.status); !reflect.DeepEqual(got, tt.want) {
   303  				t.Errorf("InvertStatus got %v, want %v", got, tt.want)
   304  			}
   305  		})
   306  	}
   307  }