Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug 2094012: UPSTREAM: 110652: fix: --chunk-size with selector returns missing result #1303

Merged
merged 1 commit into from
Jul 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion staging/src/k8s.io/apiserver/pkg/storage/etcd3/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ func growSlice(v reflect.Value, maxCapacity int, sizes ...int) {
return
}
if v.Len() > 0 {
extra := reflect.MakeSlice(v.Type(), 0, max)
extra := reflect.MakeSlice(v.Type(), v.Len(), max)
reflect.Copy(extra, v)
v.Set(extra)
} else {
Expand Down
33 changes: 31 additions & 2 deletions staging/src/k8s.io/apiserver/pkg/storage/etcd3/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2240,6 +2240,7 @@ func Test_decodeContinue(t *testing.T) {
func Test_growSlice(t *testing.T) {
type args struct {
initialCapacity int
initialLen int
v reflect.Value
maxCapacity int
sizes []int
Expand All @@ -2248,6 +2249,7 @@ func Test_growSlice(t *testing.T) {
name string
args args
cap int
len int
}{
{
name: "empty",
Expand Down Expand Up @@ -2279,13 +2281,29 @@ func Test_growSlice(t *testing.T) {
args: args{initialCapacity: 5, maxCapacity: 10, sizes: []int{8, 4}},
cap: 8,
},
{
name: "with existing capacity and length above max",
args: args{initialCapacity: 12, initialLen: 5, maxCapacity: 10, sizes: []int{8, 4}},
cap: 12,
len: 5,
},
{
name: "with existing capacity and length below max",
args: args{initialCapacity: 5, initialLen: 3, maxCapacity: 10, sizes: []int{8, 4}},
cap: 8,
len: 3,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.args.initialCapacity > 0 {
tt.args.v = reflect.ValueOf(make([]example.Pod, 0, tt.args.initialCapacity))
val := make([]example.Pod, tt.args.initialLen, tt.args.initialCapacity)
for i := 0; i < tt.args.initialLen; i++ {
val[i].Name = fmt.Sprintf("test-%d", i)
}
tt.args.v = reflect.ValueOf(val)
}
// reflection requires that the value be addressible in order to call set,
// reflection requires that the value be addressable in order to call set,
// so we must ensure the value we created is available on the heap (not a problem
// for normal usage)
if !tt.args.v.CanAddr() {
Expand All @@ -2297,6 +2315,17 @@ func Test_growSlice(t *testing.T) {
if tt.cap != tt.args.v.Cap() {
t.Errorf("Unexpected capacity: got=%d want=%d", tt.args.v.Cap(), tt.cap)
}
if tt.len != tt.args.v.Len() {
t.Errorf("Unexpected length: got=%d want=%d", tt.args.v.Len(), tt.len)
}
for i := 0; i < tt.args.v.Len(); i++ {
nameWanted := fmt.Sprintf("test-%d", i)
val := tt.args.v.Index(i).Interface()
pod, ok := val.(example.Pod)
if !ok || pod.Name != nameWanted {
t.Errorf("Unexpected element value: got=%s, want=%s", pod.Name, nameWanted)
}
}
})
}
}
Expand Down
63 changes: 63 additions & 0 deletions test/integration/apiserver/apiserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -731,6 +731,69 @@ func TestAPIListChunking(t *testing.T) {
}
}

func TestAPIListChunkingWithLabelSelector(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.APIListChunking, true)()
s, clientSet, closeFn := setup(t)
defer closeFn()

ns := framework.CreateTestingNamespace("list-paging-with-label-selector", s, t)
defer framework.DeleteTestingNamespace(ns, s, t)

rsClient := clientSet.AppsV1().ReplicaSets(ns.Name)

for i := 0; i < 10; i++ {
rs := newRS(ns.Name)
rs.Name = fmt.Sprintf("test-%d", i)
odd := i%2 != 0
rs.Labels = map[string]string{"odd-index": strconv.FormatBool(odd)}
if _, err := rsClient.Create(context.TODO(), rs, metav1.CreateOptions{}); err != nil {
t.Fatal(err)
}
}

calls := 0
firstRV := ""
p := &pager.ListPager{
PageSize: 1,
PageFn: pager.SimplePageFunc(func(opts metav1.ListOptions) (runtime.Object, error) {
calls++
list, err := rsClient.List(context.TODO(), opts)
if err != nil {
return nil, err
}
if calls == 1 {
firstRV = list.ResourceVersion
}
return list, err
}),
}
listObj, _, err := p.List(context.Background(), metav1.ListOptions{LabelSelector: "odd-index=true", Limit: 3})
if err != nil {
t.Fatal(err)
}
if calls != 2 {
t.Errorf("unexpected list invocations: %d", calls)
}
list := listObj.(metav1.ListInterface)
if len(list.GetContinue()) != 0 {
t.Errorf("unexpected continue: %s", list.GetContinue())
}
if list.GetResourceVersion() != firstRV {
t.Errorf("unexpected resource version: %s instead of %s", list.GetResourceVersion(), firstRV)
}
var names []string
if err := meta.EachListItem(listObj, func(obj runtime.Object) error {
rs := obj.(*apps.ReplicaSet)
names = append(names, rs.Name)
return nil
}); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(names, []string{"test-1", "test-3", "test-5", "test-7", "test-9"}) {
t.Errorf("unexpected items: %#v", list)
}
}

func makeSecret(name string) *v1.Secret {
return &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Expand Down