sigs.k8s.io/cluster-api@v1.7.1/util/conditions/getter_test.go (about)

     1  /*
     2  Copyright 2020 The Kubernetes 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      http://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 conditions
    18  
    19  import (
    20  	"testing"
    21  
    22  	. "github.com/onsi/gomega"
    23  
    24  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    25  )
    26  
    27  var (
    28  	nil1          *clusterv1.Condition
    29  	true1         = TrueCondition("true1")
    30  	unknown1      = UnknownCondition("unknown1", "reason unknown1", "message unknown1")
    31  	falseInfo1    = FalseCondition("falseInfo1", "reason falseInfo1", clusterv1.ConditionSeverityInfo, "message falseInfo1")
    32  	falseWarning1 = FalseCondition("falseWarning1", "reason falseWarning1", clusterv1.ConditionSeverityWarning, "message falseWarning1")
    33  	falseError1   = FalseCondition("falseError1", "reason falseError1", clusterv1.ConditionSeverityError, "message falseError1")
    34  )
    35  
    36  func TestGetAndHas(t *testing.T) {
    37  	g := NewWithT(t)
    38  
    39  	cluster := &clusterv1.Cluster{}
    40  
    41  	g.Expect(Has(cluster, "conditionBaz")).To(BeFalse())
    42  	g.Expect(Get(cluster, "conditionBaz")).To(BeNil())
    43  
    44  	cluster.SetConditions(conditionList(TrueCondition("conditionBaz")))
    45  
    46  	g.Expect(Has(cluster, "conditionBaz")).To(BeTrue())
    47  	g.Expect(Get(cluster, "conditionBaz")).To(HaveSameStateOf(TrueCondition("conditionBaz")))
    48  }
    49  
    50  func TestIsMethods(t *testing.T) {
    51  	g := NewWithT(t)
    52  
    53  	obj := getterWithConditions(nil1, true1, unknown1, falseInfo1, falseWarning1, falseError1)
    54  
    55  	// test isTrue
    56  	g.Expect(IsTrue(obj, "nil1")).To(BeFalse())
    57  	g.Expect(IsTrue(obj, "true1")).To(BeTrue())
    58  	g.Expect(IsTrue(obj, "falseInfo1")).To(BeFalse())
    59  	g.Expect(IsTrue(obj, "unknown1")).To(BeFalse())
    60  
    61  	// test isFalse
    62  	g.Expect(IsFalse(obj, "nil1")).To(BeFalse())
    63  	g.Expect(IsFalse(obj, "true1")).To(BeFalse())
    64  	g.Expect(IsFalse(obj, "falseInfo1")).To(BeTrue())
    65  	g.Expect(IsFalse(obj, "unknown1")).To(BeFalse())
    66  
    67  	// test isUnknown
    68  	g.Expect(IsUnknown(obj, "nil1")).To(BeTrue())
    69  	g.Expect(IsUnknown(obj, "true1")).To(BeFalse())
    70  	g.Expect(IsUnknown(obj, "falseInfo1")).To(BeFalse())
    71  	g.Expect(IsUnknown(obj, "unknown1")).To(BeTrue())
    72  
    73  	// test GetReason
    74  	g.Expect(GetReason(obj, "nil1")).To(Equal(""))
    75  	g.Expect(GetReason(obj, "falseInfo1")).To(Equal("reason falseInfo1"))
    76  
    77  	// test GetMessage
    78  	g.Expect(GetMessage(obj, "nil1")).To(Equal(""))
    79  	g.Expect(GetMessage(obj, "falseInfo1")).To(Equal("message falseInfo1"))
    80  
    81  	// test GetSeverity
    82  	g.Expect(GetSeverity(obj, "nil1")).To(BeNil())
    83  	severity := GetSeverity(obj, "falseInfo1")
    84  	expectedSeverity := clusterv1.ConditionSeverityInfo
    85  	g.Expect(severity).To(Equal(&expectedSeverity))
    86  
    87  	// test GetMessage
    88  	g.Expect(GetLastTransitionTime(obj, "nil1")).To(BeNil())
    89  	g.Expect(GetLastTransitionTime(obj, "falseInfo1")).ToNot(BeNil())
    90  }
    91  
    92  func TestMirror(t *testing.T) {
    93  	foo := FalseCondition("foo", "reason foo", clusterv1.ConditionSeverityInfo, "message foo")
    94  	ready := TrueCondition(clusterv1.ReadyCondition)
    95  	readyBar := ready.DeepCopy()
    96  	readyBar.Type = "bar"
    97  
    98  	tests := []struct {
    99  		name string
   100  		from Getter
   101  		t    clusterv1.ConditionType
   102  		want *clusterv1.Condition
   103  	}{
   104  		{
   105  			name: "Returns nil when the ready condition does not exists",
   106  			from: getterWithConditions(foo),
   107  			want: nil,
   108  		},
   109  		{
   110  			name: "Returns ready condition from source",
   111  			from: getterWithConditions(ready, foo),
   112  			t:    "bar",
   113  			want: readyBar,
   114  		},
   115  	}
   116  
   117  	for _, tt := range tests {
   118  		t.Run(tt.name, func(t *testing.T) {
   119  			g := NewWithT(t)
   120  
   121  			got := mirror(tt.from, tt.t)
   122  			if tt.want == nil {
   123  				g.Expect(got).To(BeNil())
   124  				return
   125  			}
   126  			g.Expect(got).To(HaveSameStateOf(tt.want))
   127  		})
   128  	}
   129  }
   130  
   131  func TestSummary(t *testing.T) {
   132  	foo := TrueCondition("foo")
   133  	bar := FalseCondition("bar", "reason falseInfo1", clusterv1.ConditionSeverityInfo, "message falseInfo1")
   134  	baz := FalseCondition("baz", "reason falseInfo2", clusterv1.ConditionSeverityInfo, "message falseInfo2")
   135  	existingReady := FalseCondition(clusterv1.ReadyCondition, "reason falseError1", clusterv1.ConditionSeverityError, "message falseError1") // NB. existing ready has higher priority than other conditions
   136  
   137  	tests := []struct {
   138  		name    string
   139  		from    Getter
   140  		options []MergeOption
   141  		want    *clusterv1.Condition
   142  	}{
   143  		{
   144  			name: "Returns nil when there are no conditions to summarize",
   145  			from: getterWithConditions(),
   146  			want: nil,
   147  		},
   148  		{
   149  			name: "Returns ready condition with the summary of existing conditions (with default options)",
   150  			from: getterWithConditions(foo, bar),
   151  			want: FalseCondition(clusterv1.ReadyCondition, "reason falseInfo1", clusterv1.ConditionSeverityInfo, "message falseInfo1"),
   152  		},
   153  		{
   154  			name:    "Returns ready condition with the summary of existing conditions (using WithStepCounter options)",
   155  			from:    getterWithConditions(foo, bar),
   156  			options: []MergeOption{WithStepCounter()},
   157  			want:    FalseCondition(clusterv1.ReadyCondition, "reason falseInfo1", clusterv1.ConditionSeverityInfo, "1 of 2 completed"),
   158  		},
   159  		{
   160  			name:    "Returns ready condition with the summary of existing conditions (using WithStepCounterIf options)",
   161  			from:    getterWithConditions(foo, bar),
   162  			options: []MergeOption{WithStepCounterIf(false)},
   163  			want:    FalseCondition(clusterv1.ReadyCondition, "reason falseInfo1", clusterv1.ConditionSeverityInfo, "message falseInfo1"),
   164  		},
   165  		{
   166  			name:    "Returns ready condition with the summary of existing conditions (using WithStepCounterIf options)",
   167  			from:    getterWithConditions(foo, bar),
   168  			options: []MergeOption{WithStepCounterIf(true)},
   169  			want:    FalseCondition(clusterv1.ReadyCondition, "reason falseInfo1", clusterv1.ConditionSeverityInfo, "1 of 2 completed"),
   170  		},
   171  		{
   172  			name:    "Returns ready condition with the summary of existing conditions (using WithStepCounterIf and WithStepCounterIfOnly options)",
   173  			from:    getterWithConditions(bar),
   174  			options: []MergeOption{WithStepCounter(), WithStepCounterIfOnly("bar")},
   175  			want:    FalseCondition(clusterv1.ReadyCondition, "reason falseInfo1", clusterv1.ConditionSeverityInfo, "0 of 1 completed"),
   176  		},
   177  		{
   178  			name:    "Returns ready condition with the summary of existing conditions (using WithStepCounterIf and WithStepCounterIfOnly options)",
   179  			from:    getterWithConditions(foo, bar),
   180  			options: []MergeOption{WithStepCounter(), WithStepCounterIfOnly("foo")},
   181  			want:    FalseCondition(clusterv1.ReadyCondition, "reason falseInfo1", clusterv1.ConditionSeverityInfo, "message falseInfo1"),
   182  		},
   183  		{
   184  			name:    "Returns ready condition with the summary of selected conditions (using WithConditions options)",
   185  			from:    getterWithConditions(foo, bar),
   186  			options: []MergeOption{WithConditions("foo")}, // bar should be ignored
   187  			want:    TrueCondition(clusterv1.ReadyCondition),
   188  		},
   189  		{
   190  			name:    "Returns ready condition with the summary of selected conditions (using WithConditions and WithStepCounter options)",
   191  			from:    getterWithConditions(foo, bar, baz),
   192  			options: []MergeOption{WithConditions("foo", "bar"), WithStepCounter()}, // baz should be ignored, total steps should be 2
   193  			want:    FalseCondition(clusterv1.ReadyCondition, "reason falseInfo1", clusterv1.ConditionSeverityInfo, "1 of 2 completed"),
   194  		},
   195  		{
   196  			name:    "Returns ready condition with the summary of selected conditions (using WithConditions and WithStepCounterIfOnly options)",
   197  			from:    getterWithConditions(bar),
   198  			options: []MergeOption{WithConditions("bar", "baz"), WithStepCounter(), WithStepCounterIfOnly("bar")}, // there is only bar, the step counter should be set and counts only a subset of conditions
   199  			want:    FalseCondition(clusterv1.ReadyCondition, "reason falseInfo1", clusterv1.ConditionSeverityInfo, "0 of 1 completed"),
   200  		},
   201  		{
   202  			name:    "Returns ready condition with the summary of selected conditions (using WithConditions and WithStepCounterIfOnly options - with inconsistent order between the two)",
   203  			from:    getterWithConditions(bar),
   204  			options: []MergeOption{WithConditions("baz", "bar"), WithStepCounter(), WithStepCounterIfOnly("bar", "baz")}, // conditions in WithStepCounterIfOnly could be in different order than in WithConditions
   205  			want:    FalseCondition(clusterv1.ReadyCondition, "reason falseInfo1", clusterv1.ConditionSeverityInfo, "0 of 2 completed"),
   206  		},
   207  		{
   208  			name:    "Returns ready condition with the summary of selected conditions (using WithConditions and WithStepCounterIfOnly options)",
   209  			from:    getterWithConditions(bar, baz),
   210  			options: []MergeOption{WithConditions("bar", "baz"), WithStepCounter(), WithStepCounterIfOnly("bar")}, // there is also baz, so the step counter should not be set
   211  			want:    FalseCondition(clusterv1.ReadyCondition, "reason falseInfo1", clusterv1.ConditionSeverityInfo, "message falseInfo1"),
   212  		},
   213  		{
   214  			name:    "Ready condition respects merge order",
   215  			from:    getterWithConditions(bar, baz),
   216  			options: []MergeOption{WithConditions("baz", "bar")}, // baz should take precedence on bar
   217  			want:    FalseCondition(clusterv1.ReadyCondition, "reason falseInfo2", clusterv1.ConditionSeverityInfo, "message falseInfo2"),
   218  		},
   219  		{
   220  			name: "Ignores existing Ready condition when computing the summary",
   221  			from: getterWithConditions(existingReady, foo, bar),
   222  			want: FalseCondition(clusterv1.ReadyCondition, "reason falseInfo1", clusterv1.ConditionSeverityInfo, "message falseInfo1"),
   223  		},
   224  	}
   225  
   226  	for _, tt := range tests {
   227  		t.Run(tt.name, func(t *testing.T) {
   228  			g := NewWithT(t)
   229  
   230  			got := summary(tt.from, tt.options...)
   231  			if tt.want == nil {
   232  				g.Expect(got).To(BeNil())
   233  				return
   234  			}
   235  			g.Expect(got).To(HaveSameStateOf(tt.want))
   236  		})
   237  	}
   238  }
   239  
   240  func TestAggregate(t *testing.T) {
   241  	ready1 := TrueCondition(clusterv1.ReadyCondition)
   242  	ready2 := FalseCondition(clusterv1.ReadyCondition, "reason falseInfo1", clusterv1.ConditionSeverityInfo, "message falseInfo1")
   243  	bar := FalseCondition("bar", "reason falseError1", clusterv1.ConditionSeverityError, "message falseError1") // NB. bar has higher priority than other conditions
   244  
   245  	tests := []struct {
   246  		name string
   247  		from []Getter
   248  		t    clusterv1.ConditionType
   249  		want *clusterv1.Condition
   250  	}{
   251  		{
   252  			name: "Returns nil when there are no conditions to aggregate",
   253  			from: []Getter{},
   254  			want: nil,
   255  		},
   256  		{
   257  			name: "Returns foo condition with the aggregation of object's ready conditions",
   258  			from: []Getter{
   259  				getterWithConditions(ready1),
   260  				getterWithConditions(ready1),
   261  				getterWithConditions(ready2, bar),
   262  				getterWithConditions(),
   263  				getterWithConditions(bar),
   264  			},
   265  			t:    "foo",
   266  			want: FalseCondition("foo", "reason falseInfo1", clusterv1.ConditionSeverityInfo, "2 of 5 completed"),
   267  		},
   268  	}
   269  
   270  	for _, tt := range tests {
   271  		t.Run(tt.name, func(t *testing.T) {
   272  			g := NewWithT(t)
   273  
   274  			got := aggregate(tt.from, tt.t)
   275  			if tt.want == nil {
   276  				g.Expect(got).To(BeNil())
   277  				return
   278  			}
   279  			g.Expect(got).To(HaveSameStateOf(tt.want))
   280  		})
   281  	}
   282  }
   283  
   284  func getterWithConditions(conditions ...*clusterv1.Condition) Getter {
   285  	obj := &clusterv1.Cluster{}
   286  	obj.SetConditions(conditionList(conditions...))
   287  	return obj
   288  }
   289  
   290  func nilGetter() Getter {
   291  	var obj *clusterv1.Cluster
   292  	return obj
   293  }
   294  
   295  func conditionList(conditions ...*clusterv1.Condition) clusterv1.Conditions {
   296  	cs := clusterv1.Conditions{}
   297  	for _, x := range conditions {
   298  		if x != nil {
   299  			cs = append(cs, *x)
   300  		}
   301  	}
   302  	return cs
   303  }