Change:
There is an integration test framework for the which provides an easy-ish way to run the server standalone for testing scenarios. See the example here: This is a running list of tests that we need to have for good coverage. [x] does the server come up [x] does basic CRUD work (e.g. kubectl create, get, delete, label, annotate) [x] does cross namespace list and watch work. [x] Proper rejects for no-namespace creates. [x] does de-registration and re-registration work [x] do multiple registrations work [x] does etcd storage function properly? Correct serialization and key location [x] does discovery for kind, shortnames, etc come through correctly [x] do colliding named resources work. And when one is deleted does the gap close [x] do non-namespaced resources work correct [x] does finalization work. [ ] do initializers work [ ] e2e test that ensures that CRDs work in [x] finalizers on CR instances should work Tests to prevent regression of issues encountered previously with TPR [x] does advanced CRUD work (e.g. kubectl edit, patch, apply, describe, explain, replace, watch) [ ] does GC behave acceptably with CustomResources as owner or owned. , blocked on Add anything missing to the list and just ping me. If you have cycles to jump in, let me know.
you had asked about specific work items. The first group of tests should be implementable now if you wanted to pick one out. If you know how to wire up a endpoint (like namespaces), that's a place to look at too.
Ok to help get in touch via slack or irc.
if you want to pick one up, let me know and I can put your name next to it.
you can put my name on "does cross namespace list and watch work. Proper rejects for no-namespace creates." For a start, I'll do a small PR.
done. I have split apart "rejects for no-namespace creates". has a test ready if I have understood her correctly.
thanks! yes, it is ready. will update the PR tomorrow and address comments.
submitted for de-registration but it fails (see )
I some new items, in a third section geared towards preventing regressions versus TPR.
xref:
All the tests are not done yet so I think this should be re-opened.
could you take "do colliding named resources work. And when one is deleted does the gap close"? You'll see this in conflicting short names. You make two CRDs, both with the same shortname. One of the two will get the name in status. The other of the two will get a NameConflict condition. When the one who has the name is updated to change its shortname, the nameconflict should be resolved for both.
I am currently working on it in this PR:
Also as an update, the test for checking if integer data is preserved is done in this PR:
there are three tests left and I think they can wait until 1.8. GC doesn't work (missing GC bits), helm is an external project that proved difficult to vendor and test, and the kube-apiserver integration is at least somewhat covered in test-
For the kube-apiserver integration can be easily extended. It bootstraps a complete kube-apiserver with the normal bootstrapping code, without any mocking.
All tests except the one for Helm are done. Does anything need to be done for Helm? If not, I believe we can close this now.
I think we can close this. Please reopen if you are missing any test coverage.

Discussion:
t.Errorf("Expected %v, got %v, %v", `9223372036854775807, 1000000`, num1, num2) } } <ins> func TestCrossNamespaceListWatch(t *testing.T) { stopCh, apiExtensionClient, clientPool, err := testserver.StartDefaultServer() if err != nil { t.Fatal(err) } defer close(stopCh) noxuDefinition := testserver.NewNoxuCustomResourceDefinition(apiextensionsv1alpha1.NamespaceScoped) noxuVersionClient, err := testserver.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, clientPool) if err != nil { t.Fatal(err) } ns := "" noxuResourceClient := NewNamespacedCustomResourceClient(ns, noxuVersionClient, noxuDefinition) initialList, err := noxuResourceClient.List(metav1.ListOptions{}) if err != nil { t.Fatal(err) } if e, a := 0, len(initialList.(*unstructured.UnstructuredList).Items); e != a { t.Errorf("expected %v, got %v", e, a) } initialListListMeta, err := meta.ListAccessor(initialList) if err != nil { t.Fatal(err) } noxuWatch, err := noxuResourceClient.Watch(metav1.ListOptions{ResourceVersion: initialListListMeta.GetResourceVersion()}) if err != nil { t.Fatal(err) } defer noxuWatch.Stop() instances := make(map[string]*unstructured.Unstructured) ns1 := "namespace-1" noxuNamespacedResourceClient1 := NewNamespacedCustomResourceClient(ns1, noxuVersionClient, noxuDefinition) instances[ns1] = createInstanceWithNamespaceHelper(t, ns1, "foo1", noxuNamespacedResourceClient1, noxuDefinition) noxuNamespacesWatch1, err := noxuNamespacedResourceClient1.Watch(metav1.ListOptions{ResourceVersion: initialListListMeta.GetResourceVersion()}) defer noxuNamespacesWatch1.Stop() ns2 := "namespace-2" noxuNamespacedResourceClient2 := NewNamespacedCustomResourceClient(ns2, noxuVersionClient, noxuDefinition) instances[ns2] = createInstanceWithNamespaceHelper(t, ns2, "foo2", noxuNamespacedResourceClient2, noxuDefinition) noxuNamespacesWatch2, err := noxuNamespacedResourceClient2.Watch(metav1.ListOptions{ResourceVersion: initialListListMeta.GetResourceVersion()}) defer noxuNamespacesWatch2.Stop() createdList, err := noxuResourceClient.List(metav1.ListOptions{}) if err != nil { t.Fatal(err) } if e, a := 2, len(createdList.(*unstructured.UnstructuredList).Items); e != a { t.Errorf("expected %v, got %v", e, a) } for _, a := range createdList.(*unstructured.UnstructuredList).Items { if e := instances[a.GetNamespace()]; !reflect.DeepEqual(e, &a) { t.Errorf("expected %v, got %v", e, a) } } addEvents := 0 for addEvents < 2 { select { case watchEvent := <-noxuWatch.ResultChan(): if e, a := watch.Added, watchEvent.Type; e != a { t.Fatalf("expected %v, got %v", e, a) } createdObjectMeta, err := meta.Accessor(watchEvent.Object) if err != nil { t.Fatal(err) } if len(createdObjectMeta.GetUID()) == 0 { t.Errorf("missing uuid: %#v", watchEvent.Object) } createdTypeMeta, err := meta.TypeAccessor(watchEvent.Object) if err != nil { t.Fatal(err) } if e, a := noxuDefinition.Spec.Group+"/"+noxuDefinition.Spec.Version, createdTypeMeta.GetAPIVersion(); e != a { t.Errorf("expected %v, got %v", e, a) } if e, a := noxuDefinition.Spec.Names.Kind, createdTypeMeta.GetKind(); e != a { t.Errorf("expected %v, got %v", e, a) } delete(instances, createdObjectMeta.GetNamespace()) addEvents++ case <-time.After(5 * time.Second): t.Fatalf("missing watch event") } } if e, a := 0, len(instances); e != a { t.Errorf("expected %v, got %v", e, a) } checkNamespacesWatchHelper(t, ns1, noxuNamespacesWatch1) checkNamespacesWatchHelper(t, ns2, noxuNamespacesWatch2) } func createInstanceWithNamespaceHelper(t *testing.T, ns string, name string, noxuNamespacedResourceClient *dynamic.ResourceClient, noxuDefinition *apiextensionsv1alpha1.CustomResourceDefinition) *unstructured.Unstructured { createdInstance, err := instantiateCustomResource(t, testserver.NewNoxuInstance(ns, name), noxuNamespacedResourceClient, noxuDefinition) if err != nil { t.Fatalf("unable to create noxu Instance:%v", err) } return createdInstance } func checkNamespacesWatchHelper(t *testing.T, ns string, namespacedwatch watch.Interface) { namespacedAddEvent := 0 for namespacedAddEvent < 2 { select { case watchEvent := <-namespacedwatch.ResultChan(): // Check that the namespaced watch only has one result if namespacedAddEvent > 0 { t.Fatalf("extra watch event") } if e, a := watch.Added, watchEvent.Type; e != a { t.Fatalf("expected %v, got %v", e, a) } createdObjectMeta, err := meta.Accessor(watchEvent.Object) if err != nil { t.Fatal(err) } if e, a := ns, createdObjectMeta.GetNamespace(); e != a { t.Errorf("expected %v, got %v", e, a) } case <-time.After(5 * time.Second): if namespacedAddEvent != 1 { t.Fatalf("missing watch event") } } namespacedAddEvent++ } } </ins>