diff --git a/test/conformance/channel_status_subscriber_test.go b/test/conformance/channel_status_subscriber_test.go new file mode 100644 index 00000000000..44a7e715160 --- /dev/null +++ b/test/conformance/channel_status_subscriber_test.go @@ -0,0 +1,30 @@ +// +build e2e + +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package conformance + +import ( + "testing" + + "knative.dev/eventing/test/conformance/helpers" + "knative.dev/eventing/test/lib" +) + +func TestChannelStatusSubscriber(t *testing.T) { + helpers.ChannelStatusSubscriberTestHelperWithChannelTestRunner(t, channelTestRunner, lib.SetupClientOptionNoop) +} diff --git a/test/conformance/helpers/channel.go b/test/conformance/helpers/channel.go index 554a9bfc9b3..097ea75da78 100644 --- a/test/conformance/helpers/channel.go +++ b/test/conformance/helpers/channel.go @@ -27,6 +27,10 @@ import ( eventingduckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" ) +const ( + SubscribableAnnotationKey = "messaging.knative.dev/subscribable" +) + func getChannelDuckTypeSupportVersion(channelName string, client *lib.Client, channel *metav1.TypeMeta) (string, error) { metaResource := resources.NewMetaResource(channelName, client.Namespace, channel) obj, err := duck.GetGenericObject(client.Dynamic, metaResource, &eventingduckv1beta1.Channelable{}) diff --git a/test/conformance/helpers/channel_status_subscriber_test_helper.go b/test/conformance/helpers/channel_status_subscriber_test_helper.go new file mode 100644 index 00000000000..1474211e9ad --- /dev/null +++ b/test/conformance/helpers/channel_status_subscriber_test_helper.go @@ -0,0 +1,128 @@ +/* +Copyright 2020 The Knative Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package helpers + +import ( + "testing" + + duckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1" + eventingv1alpha1 "knative.dev/eventing/pkg/apis/messaging/v1alpha1" + "knative.dev/eventing/test/lib" + "knative.dev/eventing/test/lib/resources" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// ChannelStatusSubscriberTestHelperWithChannelTestRunner runs the tests of +// subscriber field of status for all Channels in the ChannelTestRunner. +func ChannelStatusSubscriberTestHelperWithChannelTestRunner( + t *testing.T, + channelTestRunner lib.ChannelTestRunner, + options ...lib.SetupClientOption, +) { + + channelTestRunner.RunTests(t, lib.FeatureBasic, func(st *testing.T, channel metav1.TypeMeta) { + client := lib.Setup(st, true, options...) + defer lib.TearDown(client) + + t.Run("Channel has required status subscriber fields", func(t *testing.T) { + channelHasRequiredSubscriberStatus(st, client, channel, options...) + }) + }) +} + +func channelHasRequiredSubscriberStatus(st *testing.T, client *lib.Client, channel metav1.TypeMeta, options ...lib.SetupClientOption) { + st.Logf("Running channel subscriber status conformance test with channel %q", channel) + + channelName := "channel-req-status-subscriber" + subscriberServiceName := "channel-req-status-subscriber-svc" + + client.T.Logf("Creating channel %+v-%s", channel, channelName) + client.CreateChannelOrFail(channelName, &channel) + client.WaitForResourceReadyOrFail(channelName, &channel) + + pod := resources.EventDetailsPod(subscriberServiceName + "-pod") + client.CreatePodOrFail(pod, lib.WithService(subscriberServiceName)) + + subscription := client.CreateSubscriptionOrFail( + subscriberServiceName, + channelName, + &channel, + resources.WithSubscriberForSubscription(subscriberServiceName), + ) + + // wait for all test resources to be ready, so that we can start sending events + client.WaitForAllTestResourcesReadyOrFail() + + dtsv, err := getChannelDuckTypeSupportVersion(channelName, client, &channel) + if err != nil { + st.Fatalf("Unable to check Channel duck type support version for %q: %q", channel, err) + } + + if dtsv == "" || dtsv == "v1alpha1" { + // treat missing annotation value as v1alpha1, as written in the spec + channelable, err := getChannelAsV1Alpha1Channelable(channelName, client, channel) + if err != nil { + st.Fatalf("Unable to get channel %q to v1alpha1 duck type: %q", channel, err) + } + + // SPEC: Each subscription to a channel is added to the channel status.subscribableStatus.subscribers automatically. + if channelable.Status.SubscribableStatus == nil || channelable.Status.SubscribableStatus.Subscribers == nil { + st.Fatalf("%q does not have status.subscribers", channel) + } + ss := findSubscriberStatus(channelable.Status.SubscribableStatus.Subscribers, subscription) + if ss == nil { + st.Fatalf("No subscription status found for channel %q and subscription %v", channel, subscription) + } + + // SPEC: The ready field of the subscriber identified by its uid MUST be set to True when the subscription is ready to be processed. + if ss.Ready != corev1.ConditionTrue { + st.Fatalf("Subscription not ready found for channel %q and subscription %v", channel, subscription) + } + } else if dtsv == "v1beta1" { + channelable, err := getChannelAsV1Beta1Channelable(channelName, client, channel) + if err != nil { + st.Fatalf("Unable to get channel %q to v1beta1 duck type: %q", channel, err) + } + + // SPEC: Each subscription to a channel is added to the channel status.subscribers automatically. + if channelable.Status.Subscribers == nil { + st.Fatalf("%q does not have status.subscribers", channel) + } + ss := findSubscriberStatus(channelable.Status.Subscribers, subscription) + if ss == nil { + st.Fatalf("No subscription status found for channel %q and subscription %v", channel, subscription) + } + + // SPEC: The ready field of the subscriber identified by its uid MUST be set to True when the subscription is ready to be processed. + if ss.Ready != corev1.ConditionTrue { + st.Fatalf("Subscription not ready found for channel %q and subscription %v", channel, subscription) + } + } else { + st.Fatalf("Channel doesn't support v1alpha1 nor v1beta1 Channel duck types: %v", channel) + } +} + +func findSubscriberStatus(statusArr []duckv1beta1.SubscriberStatus, subscription *eventingv1alpha1.Subscription) *duckv1beta1.SubscriberStatus { + for _, v := range statusArr { + if v.UID == subscription.UID { + return &v + } + } + return nil +} diff --git a/test/conformance/helpers/channel_status_test_helper.go b/test/conformance/helpers/channel_status_test_helper.go index 20448cf2bc5..a40cf3c75b7 100644 --- a/test/conformance/helpers/channel_status_test_helper.go +++ b/test/conformance/helpers/channel_status_test_helper.go @@ -24,11 +24,7 @@ import ( "knative.dev/eventing/test/lib" ) -const ( - SubscribableAnnotationKey = "messaging.knative.dev/subscribable" -) - -// ChannelStatusTestHelperWithChannelTestRunner runs the Channel metadata tests for all Channels in +// ChannelStatusTestHelperWithChannelTestRunner runs the Channel status tests for all Channels in // the ChannelTestRunner. func ChannelStatusTestHelperWithChannelTestRunner( t *testing.T, @@ -49,7 +45,7 @@ func ChannelStatusTestHelperWithChannelTestRunner( func channelHasRequiredStatus(st *testing.T, client *lib.Client, channel metav1.TypeMeta, options ...lib.SetupClientOption) { st.Logf("Running channel status conformance test with channel %q", channel) - channelName := "channel-req-labels" + channelName := "channel-req-status" client.T.Logf("Creating channel %+v-%s", channel, channelName) client.CreateChannelOrFail(channelName, &channel) diff --git a/test/lib/creation.go b/test/lib/creation.go index 995aad05c5d..232ae9c70db 100644 --- a/test/lib/creation.go +++ b/test/lib/creation.go @@ -83,7 +83,7 @@ func (client *Client) CreateSubscriptionOrFail( name, channelName string, channelTypeMeta *metav1.TypeMeta, options ...resources.SubscriptionOption, -) { +) *messagingv1alpha1.Subscription { namespace := client.Namespace subscription := resources.Subscription(name, channelName, channelTypeMeta, options...) subscriptions := client.Eventing.MessagingV1alpha1().Subscriptions(namespace) @@ -94,6 +94,7 @@ func (client *Client) CreateSubscriptionOrFail( client.T.Fatalf("Failed to create subscription %q: %v", name, err) } client.Tracker.AddObj(subscription) + return subscription } // CreateSubscriptionOrFailV1Beta1 will create a Subscription or fail the test if there is an error.