Change:
By inspection, the "should receive events on concurrent watches in same order" conformance test does two things that are not stable: Starts watches from resourceVersion=0 Relies on watch connections without handling timeouts/restarts This test can fail on clusters that have configmaps autocreated in namespaces already because ordering of watch events for resourceVersion=0 watches is undefined (see ) Watch connections used by conformance tests should use well-defined ordering (starting from resourceVersions other than 0) and handle interruptions properly. Kubernetes version (use ): Cloud provider or hardware configuration: OS (e.g: ): Kernel (e.g. ): Install tools: Network plugin and version (if this is a network-related bug): Others:
There are no sig labels on this issue. Please add an appropriate label by using one of the following commands: - Please see the for a listing of the SIGs, working groups, and committees available. <detailsInstructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details
This issue is currently awaiting triage. If a SIG or subproject determines this is a relevant issue, they will accept it by applying the label and provide further guidance. The label can be by org members by writing in a comment. <detailsInstructions for interacting with me using PR comments are available . If you have questions or suggestions related to my behavior, please file an issue against the repository. </details

Discussion:
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" <ins> cachetools "k8s.io/client-go/tools/cache" watchtools "k8s.io/client-go/tools/watch" </ins> "k8s.io/kubernetes/test/e2e/framework" "github.com/onsi/ginkgo"

iterations := 100 <ins> ginkgo.By("getting a starting resourceVersion") configmaps, err := c.CoreV1().ConfigMaps(ns).List(context.TODO(), metav1.ListOptions{}) framework.ExpectNoError(err, "Failed to list configmaps in the namespace %s", ns) resourceVersion := configmaps.ResourceVersion </ins> ginkgo.By("starting a background goroutine to produce watch events") donec := make(chan struct{}) stopc := make(chan struct{})

produceConfigMapEvents(f, stopc, 5*time.Millisecond) }() <ins> listWatcher := &cachetools.ListWatch{ WatchFunc: func(listOptions metav1.ListOptions) (watch.Interface, error) { return c.CoreV1().ConfigMaps(ns).Watch(context.TODO(), listOptions) }, } </ins> ginkgo.By("creating watches starting from each resource version of the events produced and verifying they all receive resource versions in the same order") wcs := []watch.Interface{} <del> resourceVersion := "0" </del> for i := 0; i < iterations; i++ { <del> wc, err := c.CoreV1().ConfigMaps(ns).Watch(context.TODO(), metav1.ListOptions{ResourceVersion: resourceVersion}) </del> <ins> wc, err := watchtools.NewRetryWatcher(resourceVersion, listWatcher) </ins> framework.ExpectNoError(err, "Failed to watch configmaps in the namespace %s", ns) wcs = append(wcs, wc) resourceVersion = waitForNextConfigMapEvent(wcs[0]).ResourceVersion

func waitForNextConfigMapEvent(watch watch.Interface) *v1.ConfigMap { select { <del> case event := <-watch.ResultChan(): </del> <ins> case event, ok := <-watch.ResultChan(): if !ok { framework.Failf("Watch closed unexpectedly") } </ins> if configMap, ok := event.Object.(*v1.ConfigMap); ok { return configMap } <del> framework.Failf("expected config map") </del> <ins> framework.Failf("expected config map, got %T", event.Object) </ins> case <-time.After(10 * time.Second): framework.Failf("timed out waiting for watch event") }