mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Ensure empty serialized slices are zero-length, not null
This commit is contained in:
		@@ -30,6 +30,8 @@ import (
 | 
				
			|||||||
	"k8s.io/gengo/namer"
 | 
						"k8s.io/gengo/namer"
 | 
				
			||||||
	"k8s.io/gengo/types"
 | 
						"k8s.io/gengo/types"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"reflect"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/golang/glog"
 | 
						"github.com/golang/glog"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -722,6 +724,15 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip
 | 
				
			|||||||
			outMemberType = &copied
 | 
								outMemberType = &copied
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Determine if our destination field is a slice that should be output when empty.
 | 
				
			||||||
 | 
							// If it is, ensure a nil source slice converts to a zero-length destination slice.
 | 
				
			||||||
 | 
							// See http://issue.k8s.io/43203
 | 
				
			||||||
 | 
							persistEmptySlice := false
 | 
				
			||||||
 | 
							if outMemberType.Kind == types.Slice {
 | 
				
			||||||
 | 
								jsonTag := reflect.StructTag(outMember.Tags).Get("json")
 | 
				
			||||||
 | 
								persistEmptySlice = len(jsonTag) > 0 && !strings.Contains(jsonTag, ",omitempty")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		args := argsFromType(inMemberType, outMemberType).With("name", inMember.Name)
 | 
							args := argsFromType(inMemberType, outMemberType).With("name", inMember.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// try a direct memory copy for any type that has exactly equivalent values
 | 
							// try a direct memory copy for any type that has exactly equivalent values
 | 
				
			||||||
@@ -737,7 +748,15 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip
 | 
				
			|||||||
				sw.Do("out.$.name$ = *(*$.outType|raw$)($.Pointer|raw$(&in.$.name$))\n", args)
 | 
									sw.Do("out.$.name$ = *(*$.outType|raw$)($.Pointer|raw$(&in.$.name$))\n", args)
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
			case types.Slice:
 | 
								case types.Slice:
 | 
				
			||||||
 | 
									if persistEmptySlice {
 | 
				
			||||||
 | 
										sw.Do("if in.$.name$ == nil {\n", args)
 | 
				
			||||||
 | 
										sw.Do("out.$.name$ = make($.outType|raw$, 0)\n", args)
 | 
				
			||||||
 | 
										sw.Do("} else {\n", nil)
 | 
				
			||||||
					sw.Do("out.$.name$ = *(*$.outType|raw$)($.Pointer|raw$(&in.$.name$))\n", args)
 | 
										sw.Do("out.$.name$ = *(*$.outType|raw$)($.Pointer|raw$(&in.$.name$))\n", args)
 | 
				
			||||||
 | 
										sw.Do("}\n", nil)
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										sw.Do("out.$.name$ = *(*$.outType|raw$)($.Pointer|raw$(&in.$.name$))\n", args)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
				continue
 | 
									continue
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -787,7 +806,11 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip
 | 
				
			|||||||
			sw.Do("in, out := &in.$.name$, &out.$.name$\n", args)
 | 
								sw.Do("in, out := &in.$.name$, &out.$.name$\n", args)
 | 
				
			||||||
			g.generateFor(inMemberType, outMemberType, sw)
 | 
								g.generateFor(inMemberType, outMemberType, sw)
 | 
				
			||||||
			sw.Do("} else {\n", nil)
 | 
								sw.Do("} else {\n", nil)
 | 
				
			||||||
 | 
								if persistEmptySlice {
 | 
				
			||||||
 | 
									sw.Do("out.$.name$ = make($.outType|raw$, 0)\n", args)
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
				sw.Do("out.$.name$ = nil\n", args)
 | 
									sw.Do("out.$.name$ = nil\n", args)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			sw.Do("}\n", nil)
 | 
								sw.Do("}\n", nil)
 | 
				
			||||||
		case types.Struct:
 | 
							case types.Struct:
 | 
				
			||||||
			if g.isDirectlyAssignable(inMemberType, outMemberType) {
 | 
								if g.isDirectlyAssignable(inMemberType, outMemberType) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,7 @@ import (
 | 
				
			|||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apiequality "k8s.io/apimachinery/pkg/api/equality"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/intstr"
 | 
						"k8s.io/apimachinery/pkg/util/intstr"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api"
 | 
						"k8s.io/kubernetes/pkg/api"
 | 
				
			||||||
@@ -173,7 +174,7 @@ func TestSetDefaultDeployment(t *testing.T) {
 | 
				
			|||||||
			t.Errorf("unexpected object: %v", got)
 | 
								t.Errorf("unexpected object: %v", got)
 | 
				
			||||||
			t.FailNow()
 | 
								t.FailNow()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if !reflect.DeepEqual(got.Spec, expected.Spec) {
 | 
							if !apiequality.Semantic.DeepEqual(got.Spec, expected.Spec) {
 | 
				
			||||||
			t.Errorf("object mismatch!\nexpected:\n\t%+v\ngot:\n\t%+v", got.Spec, expected.Spec)
 | 
								t.Errorf("object mismatch!\nexpected:\n\t%+v\ngot:\n\t%+v", got.Spec, expected.Spec)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,7 @@ import (
 | 
				
			|||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apiequality "k8s.io/apimachinery/pkg/api/equality"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/api/resource"
 | 
						"k8s.io/apimachinery/pkg/api/resource"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
@@ -156,7 +157,7 @@ func TestSetDefaultDaemonSet(t *testing.T) {
 | 
				
			|||||||
			t.Errorf("(%d) unexpected object: %v", i, got)
 | 
								t.Errorf("(%d) unexpected object: %v", i, got)
 | 
				
			||||||
			t.FailNow()
 | 
								t.FailNow()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if !reflect.DeepEqual(got.Spec, expected.Spec) {
 | 
							if !apiequality.Semantic.DeepEqual(got.Spec, expected.Spec) {
 | 
				
			||||||
			t.Errorf("(%d) got different than expected\ngot:\n\t%+v\nexpected:\n\t%+v", i, got.Spec, expected.Spec)
 | 
								t.Errorf("(%d) got different than expected\ngot:\n\t%+v\nexpected:\n\t%+v", i, got.Spec, expected.Spec)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -295,7 +296,7 @@ func TestSetDefaultDeployment(t *testing.T) {
 | 
				
			|||||||
			t.Errorf("unexpected object: %v", got)
 | 
								t.Errorf("unexpected object: %v", got)
 | 
				
			||||||
			t.FailNow()
 | 
								t.FailNow()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if !reflect.DeepEqual(got.Spec, expected.Spec) {
 | 
							if !apiequality.Semantic.DeepEqual(got.Spec, expected.Spec) {
 | 
				
			||||||
			t.Errorf("object mismatch!\nexpected:\n\t%+v\ngot:\n\t%+v", got.Spec, expected.Spec)
 | 
								t.Errorf("object mismatch!\nexpected:\n\t%+v\ngot:\n\t%+v", got.Spec, expected.Spec)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,12 +25,12 @@ import (
 | 
				
			|||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"os/user"
 | 
						"os/user"
 | 
				
			||||||
	"path"
 | 
						"path"
 | 
				
			||||||
	"reflect"
 | 
					 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apiequality "k8s.io/apimachinery/pkg/api/equality"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/api/meta"
 | 
						"k8s.io/apimachinery/pkg/api/meta"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/labels"
 | 
						"k8s.io/apimachinery/pkg/labels"
 | 
				
			||||||
@@ -623,7 +623,7 @@ func TestGetFirstPod(t *testing.T) {
 | 
				
			|||||||
			t.Errorf("%s: expected %d pods, got %d", test.name, test.expectedNum, numPods)
 | 
								t.Errorf("%s: expected %d pods, got %d", test.name, test.expectedNum, numPods)
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if !reflect.DeepEqual(test.expected, pod) {
 | 
							if !apiequality.Semantic.DeepEqual(test.expected, pod) {
 | 
				
			||||||
			t.Errorf("%s:\nexpected pod:\n%#v\ngot:\n%#v\n\n", test.name, test.expected, pod)
 | 
								t.Errorf("%s:\nexpected pod:\n%#v\ngot:\n%#v\n\n", test.name, test.expected, pod)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,11 +21,11 @@ import (
 | 
				
			|||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"reflect"
 | 
					 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"syscall"
 | 
						"syscall"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apiequality "k8s.io/apimachinery/pkg/api/equality"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/api/errors"
 | 
						"k8s.io/apimachinery/pkg/api/errors"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/api/meta"
 | 
						"k8s.io/apimachinery/pkg/api/meta"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
@@ -194,7 +194,7 @@ func TestMerge(t *testing.T) {
 | 
				
			|||||||
		if !test.expectErr {
 | 
							if !test.expectErr {
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				t.Errorf("testcase[%d], unexpected error: %v", i, err)
 | 
									t.Errorf("testcase[%d], unexpected error: %v", i, err)
 | 
				
			||||||
			} else if !reflect.DeepEqual(out, test.expected) {
 | 
								} else if !apiequality.Semantic.DeepEqual(out, test.expected) {
 | 
				
			||||||
				t.Errorf("\n\ntestcase[%d]\nexpected:\n%+v\nsaw:\n%+v", i, test.expected, out)
 | 
									t.Errorf("\n\ntestcase[%d]\nexpected:\n%+v\nsaw:\n%+v", i, test.expected, out)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -374,7 +374,7 @@ func TestMaybeConvert(t *testing.T) {
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Errorf("unexpected error: %v", err)
 | 
								t.Errorf("unexpected error: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if !reflect.DeepEqual(test.expected, obj) {
 | 
							if !apiequality.Semantic.DeepEqual(test.expected, obj) {
 | 
				
			||||||
			t.Errorf("expected:\n%#v\nsaw:\n%#v\n", test.expected, obj)
 | 
								t.Errorf("expected:\n%#v\nsaw:\n%#v\n", test.expected, obj)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -556,7 +556,7 @@ func TestResourceByName(t *testing.T) {
 | 
				
			|||||||
	if err != nil || !singleItemImplied || len(test.Infos) != 1 {
 | 
						if err != nil || !singleItemImplied || len(test.Infos) != 1 {
 | 
				
			||||||
		t.Fatalf("unexpected response: %v %t %#v", err, singleItemImplied, test.Infos)
 | 
							t.Fatalf("unexpected response: %v %t %#v", err, singleItemImplied, test.Infos)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !reflect.DeepEqual(&pods.Items[0], test.Objects()[0]) {
 | 
						if !apiequality.Semantic.DeepEqual(&pods.Items[0], test.Objects()[0]) {
 | 
				
			||||||
		t.Errorf("unexpected object: %#v", test.Objects()[0])
 | 
							t.Errorf("unexpected object: %#v", test.Objects()[0])
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -621,10 +621,10 @@ func TestResourceNames(t *testing.T) {
 | 
				
			|||||||
	if err != nil || len(test.Infos) != 2 {
 | 
						if err != nil || len(test.Infos) != 2 {
 | 
				
			||||||
		t.Fatalf("unexpected response: %v %#v", err, test.Infos)
 | 
							t.Fatalf("unexpected response: %v %#v", err, test.Infos)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !reflect.DeepEqual(&pods.Items[0], test.Objects()[0]) {
 | 
						if !apiequality.Semantic.DeepEqual(&pods.Items[0], test.Objects()[0]) {
 | 
				
			||||||
		t.Errorf("unexpected object: \n%#v, expected: \n%#v", test.Objects()[0], &pods.Items[0])
 | 
							t.Errorf("unexpected object: \n%#v, expected: \n%#v", test.Objects()[0], &pods.Items[0])
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !reflect.DeepEqual(&svc.Items[0], test.Objects()[1]) {
 | 
						if !apiequality.Semantic.DeepEqual(&svc.Items[0], test.Objects()[1]) {
 | 
				
			||||||
		t.Errorf("unexpected object: \n%#v, expected: \n%#v", test.Objects()[1], &svc.Items[0])
 | 
							t.Errorf("unexpected object: \n%#v, expected: \n%#v", test.Objects()[1], &svc.Items[0])
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -698,7 +698,7 @@ func TestResourceByNameAndEmptySelector(t *testing.T) {
 | 
				
			|||||||
	if err != nil || !singleItemImplied || len(infos) != 1 {
 | 
						if err != nil || !singleItemImplied || len(infos) != 1 {
 | 
				
			||||||
		t.Fatalf("unexpected response: %v %t %#v", err, singleItemImplied, infos)
 | 
							t.Fatalf("unexpected response: %v %t %#v", err, singleItemImplied, infos)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if !reflect.DeepEqual(&pods.Items[0], infos[0].Object) {
 | 
						if !apiequality.Semantic.DeepEqual(&pods.Items[0], infos[0].Object) {
 | 
				
			||||||
		t.Errorf("unexpected object: %#v", infos[0])
 | 
							t.Errorf("unexpected object: %#v", infos[0])
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,7 @@ import (
 | 
				
			|||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						apiequality "k8s.io/apimachinery/pkg/api/equality"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/api/errors"
 | 
						"k8s.io/apimachinery/pkg/api/errors"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/runtime"
 | 
						"k8s.io/apimachinery/pkg/runtime"
 | 
				
			||||||
@@ -1475,7 +1476,7 @@ func TestUpdateRcWithRetries(t *testing.T) {
 | 
				
			|||||||
				updates = updates[1:]
 | 
									updates = updates[1:]
 | 
				
			||||||
				// We should always get an update with a valid rc even when the get fails. The rc should always
 | 
									// We should always get an update with a valid rc even when the get fails. The rc should always
 | 
				
			||||||
				// contain the update.
 | 
									// contain the update.
 | 
				
			||||||
				if c, ok := readOrDie(t, req, codec).(*api.ReplicationController); !ok || !reflect.DeepEqual(rc, c) {
 | 
									if c, ok := readOrDie(t, req, codec).(*api.ReplicationController); !ok || !apiequality.Semantic.DeepEqual(rc, c) {
 | 
				
			||||||
					t.Errorf("Unexpected update body, got %+v expected %+v", c, rc)
 | 
										t.Errorf("Unexpected update body, got %+v expected %+v", c, rc)
 | 
				
			||||||
				} else if sel, ok := c.Spec.Selector["baz"]; !ok || sel != "foobar" {
 | 
									} else if sel, ok := c.Spec.Selector["baz"]; !ok || sel != "foobar" {
 | 
				
			||||||
					t.Errorf("Expected selector label update, got %+v", c.Spec.Selector)
 | 
										t.Errorf("Expected selector label update, got %+v", c.Spec.Selector)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user