56448506075c3db1d added support for List+Watch to a fake client-go instance.
However, that support was not quite working yet as seen when analyzing a test
flake:
- List returned early when there were no objects, without adding the
ResourceVersion. The ResourceVersion should have been "0" instead.
- When encountering "" as ResourceVersion, Watch didn't deliver
any objects. That was meant to preserve compatibility with clients
which don't expect objects from a Watch, but the right semantic of
"" is "Start at most recent", which includes delivering existing
objects.
Tests which meddle with the List implementation via a reactor (like
clustertrustbundlepublisher) have to be aware that Watch now may
return objects when given an empty ResourceVersion.
Kubernetes-commit: 6bfa727bee264f5d7e4471066c1b48a28d0c1929
Quite a lot of unit tests set up informers with a fake client, do
informerFactory.WaitForCacheSync, then create or modify objects. Such tests
suffered from a race: because the fake client only delivered objects to the
watch after the watch has been created, creating an object too early caused
that object to not get delivered to the informer.
Usually the timing worked out okay because WaitForCacheSync typically slept a
bit while polling, giving the Watch call time to complete, but this race has
also gone wrong occasionally. Now with WaitForCacheSync returning more promptly
without polling (work in progress), the race goes wrong more often.
Instead of working around this in unit tests it's better to improve the fake
client such that List+Watch works reliably, regardless of the timing. The fake
client has traditionally not touched ResourceVersion in stored objects and
doing so now might break unit tests, so the added support for ResourceVersion
is intentionally limited to List+Watch.
The test simulates "real" usage of informers. It runs in a synctest bubble and
completes quickly:
go test -v .
=== RUN TestListAndWatch
listandwatch_test.go:67: I0101 01:00:00.000000] Listed configMaps="&ConfigMapList{ListMeta:{ 1 <nil>},Items:[]ConfigMap{ConfigMap{ObjectMeta:{cm1 default 0 0001-01-01 00:00:00 +0000 UTC <nil> <nil> map[] map[] [] [] []},Data:map[string]string{},BinaryData:map[string][]byte{},Immutable:nil,},},}" err=null
listandwatch_test.go:79: I0101 01:00:00.000000] Delaying Watch...
listandwatch_test.go:90: I0101 01:00:00.100000] Caches synced
listandwatch_test.go:107: I0101 01:00:00.100000] Created second ConfigMap
listandwatch_test.go:81: I0101 01:00:00.100000] Continuing Watch...
--- PASS: TestListAndWatch (0.00s)
PASS
ok k8s.io/client-go/testing/internal 0.009s
Some users of the fake client need to be updated to avoid test failures:
- ListMeta comparisons have to be updated.
- Optional: pass ListOptions into tracker.Watch. It's optional because
the implementation behaves as before when options are missing,
but the List+Watch race fix only works when options are passed.
Kubernetes-commit: 56448506075c3db1d16b5bbf0c581b833a4646f1
With the introduction of GVK to the fake dynamic client it made using
the fake much more cumbersome.
Specifically:
- requires manual registration of list types
- mismatch between scheme types and passed in fixtures would result in errors
The PR changes the constructor method NewSimpleDynamicClient to do the following:
- rewire the schemes to unstructured types
- typed fixtures are converted to unstructured types
- automatically register fixture gvks with the scheme
This should make the dynamic client 'flexible' with it's inputs like it was
before
Kubernetes-commit: 418fa71b6b1d1fba930daaba1f8ecf55070b4bdf
Today the dynamic fake client is not aware of *List kinds, so List calls return UnstructuredList
objects without TypeMeta. This patch updates client-go's fake object tracker to store a map of
GVR to list GVKs. In this way, the list GVK can be set for UnstructuredList objects.
Signed-off-by: Andrew Sy Kim <kim.andrewsy@gmail.com>
Kubernetes-commit: 0845b863e89912e0d6c4380f8bc362646326386a
The fake clientset used a slice to store each kind of objects, it's
quite slow to init the clientset with massive objects because it checked
existence of an object by traversing all objects before adding it, which
leads to O(n^2) time complexity. Also, the Create, Update, Get, Delete
methods needs to traverse all objects, which affects the time statistic
of code that calls them.
This patch changed to use a map to store each kind of objects, reduced
the time complexity of initializing clientset to O(n) and the Create,
Update, Get, Delete to O(1).
For example:
Before this patch, it took ~29s to init a clientset with 30000 Pods,
and 2~4ms to create and get an Pod.
After this patch, it took ~50ms to init a clientset with 30000 Pods,
and tens of µs to create and get an Pod.
Kubernetes-commit: 7e15e31e11e48a6db855e30ca9b07dbce3047577
This introduces fake implementations of dynamic.Client and
dynamic.ClientPool. They function similarly to the fake generated
clientsets, since they're also based in testing.Fake.
Kubernetes-commit: 3e6bf24e08645512a7b40d91bd61f0f2ea175026