diff --git a/conformance/utils/kubernetes/helpers.go b/conformance/utils/kubernetes/helpers.go index f0294663f9..093cc7dbda 100644 --- a/conformance/utils/kubernetes/helpers.go +++ b/conformance/utils/kubernetes/helpers.go @@ -147,13 +147,14 @@ func ConditionsHaveLatestObservedGeneration(obj metav1.Object, conditions []meta return nil } + wantGeneration := obj.GetGeneration() var b strings.Builder - fmt.Fprint(&b, "expected observedGeneration to be updated for all conditions") + fmt.Fprintf(&b, "expected observedGeneration to be updated to %d for all conditions", wantGeneration) fmt.Fprintf(&b, ", only %d/%d were updated.", len(conditions)-len(staleConditions), len(conditions)) fmt.Fprintf(&b, " stale conditions are: ") for i, c := range staleConditions { - fmt.Fprintf(&b, c.Type) + fmt.Fprintf(&b, "%s (generation %d)", c.Type, c.ObservedGeneration) if i != len(staleConditions)-1 { fmt.Fprintf(&b, ", ") } diff --git a/conformance/utils/kubernetes/helpers_test.go b/conformance/utils/kubernetes/helpers_test.go index dc7812b265..3e1158db89 100644 --- a/conformance/utils/kubernetes/helpers_test.go +++ b/conformance/utils/kubernetes/helpers_test.go @@ -17,14 +17,126 @@ limitations under the License. package kubernetes import ( + "fmt" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/gateway-api/apis/v1alpha2" "sigs.k8s.io/gateway-api/apis/v1beta1" ) +// ----------------------------------------------------------------------------- +// Test - Public Functions +// ----------------------------------------------------------------------------- + +func TestNewGatewayRef(t *testing.T) { + tests := []struct { + name string + nsn types.NamespacedName + listenerNames []string + }{ + { + name: "verifying the contents of a GatewayRef with no provided listeners", + nsn: types.NamespacedName{Namespace: corev1.NamespaceDefault, Name: "fake-gateway"}, + }, + { + name: "verifying the contents of a GatewayRef listeners with one listener provided", + nsn: types.NamespacedName{Namespace: corev1.NamespaceDefault, Name: "fake-gateway"}, + listenerNames: []string{"fake-listener-1"}, + }, + { + name: "verifying the contents of a GatewayRef listeners with multiple listeners provided", + nsn: types.NamespacedName{Namespace: corev1.NamespaceDefault, Name: "fake-gateway"}, + listenerNames: []string{ + "fake-listener-1", + "fake-listener-2", + "fake-listener-3", + }, + }, + } + + for i := 0; i < len(tests); i++ { + test := tests[i] + t.Run(test.name, func(t *testing.T) { + ref := NewGatewayRef(test.nsn, test.listenerNames...) + require.IsType(t, GatewayRef{}, ref) + if test.listenerNames == nil { + require.Len(t, ref.listenerNames, 1) + assert.Equal(t, "", string(*ref.listenerNames[0])) + } else { + require.Len(t, ref.listenerNames, len(test.listenerNames)) + for i := 0; i < len(ref.listenerNames); i++ { + assert.Equal(t, test.listenerNames[i], string(*ref.listenerNames[i])) + } + } + assert.Equal(t, test.nsn, ref.NamespacedName) + }) + } +} + +func TestVerifyConditionsMatchGeneration(t *testing.T) { + tests := []struct { + name string + obj metav1.Object + conditions []metav1.Condition + expected error + }{ + {}, + { + name: "if no conditions are provided this technically passes verification", + }, + { + name: "conditions where all match the generation pass verification", + obj: &v1beta1.Gateway{ObjectMeta: metav1.ObjectMeta{Name: "fake-gateway", Generation: 20}}, + conditions: []metav1.Condition{ + {Type: "FakeCondition1", ObservedGeneration: 20}, + {Type: "FakeCondition2", ObservedGeneration: 20}, + {Type: "FakeCondition3", ObservedGeneration: 20}, + }, + }, + { + name: "conditions where one does not match the generation fail verification", + obj: &v1beta1.Gateway{ObjectMeta: metav1.ObjectMeta{Name: "fake-gateway", Generation: 20}}, + conditions: []metav1.Condition{ + {Type: "FakeCondition1", ObservedGeneration: 20}, + {Type: "FakeCondition2", ObservedGeneration: 19}, + {Type: "FakeCondition3", ObservedGeneration: 20}, + }, + expected: fmt.Errorf("expected observedGeneration to be updated to 20 for all conditions, only 2/3 were updated. stale conditions are: FakeCondition2 (generation 19)"), + }, + { + name: "conditions where most do not match the generation fail verification", + obj: &v1beta1.Gateway{ObjectMeta: metav1.ObjectMeta{Name: "fake-gateway", Generation: 20}}, + conditions: []metav1.Condition{ + {Type: "FakeCondition1", ObservedGeneration: 18}, + {Type: "FakeCondition2", ObservedGeneration: 18}, + {Type: "FakeCondition3", ObservedGeneration: 14}, + {Type: "FakeCondition4", ObservedGeneration: 20}, + {Type: "FakeCondition5", ObservedGeneration: 16}, + {Type: "FakeCondition6", ObservedGeneration: 15}, + }, + expected: fmt.Errorf("expected observedGeneration to be updated to 20 for all conditions, only 1/6 were updated. stale conditions are: FakeCondition1 (generation 18), FakeCondition2 (generation 18), FakeCondition3 (generation 14), FakeCondition5 (generation 16), FakeCondition6 (generation 15)"), + }, + } + + for i := 0; i < len(tests); i++ { + test := tests[i] + t.Run(test.name, func(t *testing.T) { + err := ConditionsHaveLatestObservedGeneration(test.obj, test.conditions) + assert.Equal(t, test.expected, err) + }) + } +} + +// ----------------------------------------------------------------------------- +// Test - Private Functions +// ----------------------------------------------------------------------------- + func Test_listenersMatch(t *testing.T) { tests := []struct { name string