mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	add a unit test
This commit is contained in:
		@@ -191,6 +191,7 @@ go_test(
 | 
				
			|||||||
        "//pkg/runtime/serializer/streaming:go_default_library",
 | 
					        "//pkg/runtime/serializer/streaming:go_default_library",
 | 
				
			||||||
        "//pkg/types:go_default_library",
 | 
					        "//pkg/types:go_default_library",
 | 
				
			||||||
        "//pkg/util/intstr:go_default_library",
 | 
					        "//pkg/util/intstr:go_default_library",
 | 
				
			||||||
 | 
					        "//pkg/util/strategicpatch:go_default_library",
 | 
				
			||||||
        "//pkg/util/strings:go_default_library",
 | 
					        "//pkg/util/strings:go_default_library",
 | 
				
			||||||
        "//pkg/util/term:go_default_library",
 | 
					        "//pkg/util/term:go_default_library",
 | 
				
			||||||
        "//pkg/util/wait:go_default_library",
 | 
					        "//pkg/util/wait:go_default_library",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@ import (
 | 
				
			|||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"net/http"
 | 
						"net/http"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/spf13/cobra"
 | 
						"github.com/spf13/cobra"
 | 
				
			||||||
@@ -37,6 +38,7 @@ import (
 | 
				
			|||||||
	cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
 | 
						cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
 | 
				
			||||||
	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
 | 
						cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/runtime"
 | 
						"k8s.io/kubernetes/pkg/runtime"
 | 
				
			||||||
 | 
						"k8s.io/kubernetes/pkg/util/strategicpatch"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestApplyExtraArgsFail(t *testing.T) {
 | 
					func TestApplyExtraArgsFail(t *testing.T) {
 | 
				
			||||||
@@ -142,6 +144,58 @@ func readAndAnnotateService(t *testing.T, filename string) (string, []byte) {
 | 
				
			|||||||
	return annotateRuntimeObject(t, svc1, svc2, "Service")
 | 
						return annotateRuntimeObject(t, svc1, svc2, "Service")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func setFinalizersRuntimeObject(t *testing.T, originalObj, currentObj runtime.Object) (string, []byte) {
 | 
				
			||||||
 | 
						originalAccessor, err := meta.Accessor(originalObj)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						originalFinalizers := []string{"a/a"}
 | 
				
			||||||
 | 
						originalAccessor.SetFinalizers(originalFinalizers)
 | 
				
			||||||
 | 
						original, err := runtime.Encode(testapi.Default.Codec(), originalObj)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						currentAccessor, err := meta.Accessor(currentObj)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						currentFinalizers := []string{"b/b"}
 | 
				
			||||||
 | 
						currentAccessor.SetFinalizers(currentFinalizers)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						currentAnnotations := currentAccessor.GetAnnotations()
 | 
				
			||||||
 | 
						if currentAnnotations == nil {
 | 
				
			||||||
 | 
							currentAnnotations = make(map[string]string)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						currentAnnotations[annotations.LastAppliedConfigAnnotation] = string(original)
 | 
				
			||||||
 | 
						currentAccessor.SetAnnotations(currentAnnotations)
 | 
				
			||||||
 | 
						current, err := runtime.Encode(testapi.Default.Codec(), currentObj)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return currentAccessor.GetName(), current
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func readAndSetFinalizersReplicationController(t *testing.T, filename string) (string, []byte) {
 | 
				
			||||||
 | 
						rc1 := readReplicationControllerFromFile(t, filename)
 | 
				
			||||||
 | 
						rc2 := readReplicationControllerFromFile(t, filename)
 | 
				
			||||||
 | 
						name, rcBytes := setFinalizersRuntimeObject(t, rc1, rc2)
 | 
				
			||||||
 | 
						return name, rcBytes
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func isSMPatchVersion_1_5(t *testing.T, req *http.Request) bool {
 | 
				
			||||||
 | 
						patch, err := ioutil.ReadAll(req.Body)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// SMPatchVersion_1_5 patch should has string "mergeprimitiveslist"
 | 
				
			||||||
 | 
						return strings.Contains(string(patch), strategicpatch.MergePrimitivesListDirective)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func validatePatchApplication(t *testing.T, req *http.Request) {
 | 
					func validatePatchApplication(t *testing.T, req *http.Request) {
 | 
				
			||||||
	patch, err := ioutil.ReadAll(req.Body)
 | 
						patch, err := ioutil.ReadAll(req.Body)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -223,6 +277,65 @@ func TestApplyObject(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestApplyRetryWithSMPatchVersion_1_5(t *testing.T) {
 | 
				
			||||||
 | 
						initTestErrorHandler(t)
 | 
				
			||||||
 | 
						nameRC, currentRC := readAndSetFinalizersReplicationController(t, filenameRC)
 | 
				
			||||||
 | 
						pathRC := "/namespaces/test/replicationcontrollers/" + nameRC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						firstPatch := true
 | 
				
			||||||
 | 
						retry := false
 | 
				
			||||||
 | 
						f, tf, _, ns := cmdtesting.NewAPIFactory()
 | 
				
			||||||
 | 
						tf.Printer = &testPrinter{}
 | 
				
			||||||
 | 
						tf.Client = &fake.RESTClient{
 | 
				
			||||||
 | 
							NegotiatedSerializer: ns,
 | 
				
			||||||
 | 
							Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
 | 
				
			||||||
 | 
								switch p, m := req.URL.Path, req.Method; {
 | 
				
			||||||
 | 
								case p == pathRC && m == "GET":
 | 
				
			||||||
 | 
									bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
 | 
				
			||||||
 | 
									return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
 | 
				
			||||||
 | 
								case p == pathRC && m == "PATCH":
 | 
				
			||||||
 | 
									if firstPatch {
 | 
				
			||||||
 | 
										if !isSMPatchVersion_1_5(t, req) {
 | 
				
			||||||
 | 
											t.Fatalf("apply didn't try to send SMPatchVersion_1_5 for the first time")
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										firstPatch = false
 | 
				
			||||||
 | 
										statusErr := kubeerr.NewInternalError(fmt.Errorf("Server encountered internal error."))
 | 
				
			||||||
 | 
										bodyBytes, _ := json.Marshal(statusErr)
 | 
				
			||||||
 | 
										bodyErr := ioutil.NopCloser(bytes.NewReader(bodyBytes))
 | 
				
			||||||
 | 
										return &http.Response{StatusCode: http.StatusInternalServerError, Header: defaultHeader(), Body: bodyErr}, nil
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									retry = true
 | 
				
			||||||
 | 
									if isSMPatchVersion_1_5(t, req) {
 | 
				
			||||||
 | 
										t.Fatalf("apply didn't try to send SMPatchVersion_1_0 after SMPatchVersion_1_5 patch encounter an Internal Error (500)")
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									bodyRC := ioutil.NopCloser(bytes.NewReader(currentRC))
 | 
				
			||||||
 | 
									return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: bodyRC}, nil
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									t.Fatalf("unexpected request: %#v\n%#v", req.URL, req)
 | 
				
			||||||
 | 
									return nil, nil
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						tf.Namespace = "test"
 | 
				
			||||||
 | 
						tf.ClientConfig = defaultClientConfig()
 | 
				
			||||||
 | 
						buf := bytes.NewBuffer([]byte{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cmd := NewCmdApply(f, buf)
 | 
				
			||||||
 | 
						cmd.Flags().Set("filename", filenameRC)
 | 
				
			||||||
 | 
						cmd.Flags().Set("output", "name")
 | 
				
			||||||
 | 
						cmd.Run(cmd, []string{})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if !retry {
 | 
				
			||||||
 | 
							t.Fatalf("apply didn't retry when get Internal Error (500)")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// uses the name from the file, not the response
 | 
				
			||||||
 | 
						expectRC := "replicationcontroller/" + nameRC + "\n"
 | 
				
			||||||
 | 
						if buf.String() != expectRC {
 | 
				
			||||||
 | 
							t.Fatalf("unexpected output: %s\nexpected: %s", buf.String(), expectRC)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestApplyRetry(t *testing.T) {
 | 
					func TestApplyRetry(t *testing.T) {
 | 
				
			||||||
	initTestErrorHandler(t)
 | 
						initTestErrorHandler(t)
 | 
				
			||||||
	nameRC, currentRC := readAndAnnotateReplicationController(t, filenameRC)
 | 
						nameRC, currentRC := readAndAnnotateReplicationController(t, filenameRC)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -427,8 +427,12 @@ func (f *fakeAPIFactory) UnstructuredObject() (meta.RESTMapper, runtime.ObjectTy
 | 
				
			|||||||
	return cmdutil.NewShortcutExpander(mapper, nil), typer, nil
 | 
						return cmdutil.NewShortcutExpander(mapper, nil), typer, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (f *fakeAPIFactory) Decoder(bool) runtime.Decoder {
 | 
					func (f *fakeAPIFactory) Decoder(toInternal bool) runtime.Decoder {
 | 
				
			||||||
	return testapi.Default.Codec()
 | 
						if toInternal {
 | 
				
			||||||
 | 
							return api.Codecs.UniversalDecoder()
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							return api.Codecs.UniversalDeserializer()
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (f *fakeAPIFactory) JSONEncoder() runtime.Encoder {
 | 
					func (f *fakeAPIFactory) JSONEncoder() runtime.Encoder {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,7 +45,7 @@ const (
 | 
				
			|||||||
	deleteDirective              = "delete"
 | 
						deleteDirective              = "delete"
 | 
				
			||||||
	replaceDirective             = "replace"
 | 
						replaceDirective             = "replace"
 | 
				
			||||||
	mergeDirective               = "merge"
 | 
						mergeDirective               = "merge"
 | 
				
			||||||
	mergePrimitivesListDirective = "mergeprimitiveslist"
 | 
						MergePrimitivesListDirective = "mergeprimitiveslist"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// different versions of StrategicMergePatch
 | 
						// different versions of StrategicMergePatch
 | 
				
			||||||
	SMPatchVersion_1_0   StrategicMergePatchVersion = "v1.0.0"
 | 
						SMPatchVersion_1_0   StrategicMergePatchVersion = "v1.0.0"
 | 
				
			||||||
@@ -393,7 +393,7 @@ loopB:
 | 
				
			|||||||
func diffListsOfScalarsIntoMap(originalScalars, modifiedScalars []interface{}, ignoreChangesAndAdditions, ignoreDeletions bool) (map[string]interface{}, error) {
 | 
					func diffListsOfScalarsIntoMap(originalScalars, modifiedScalars []interface{}, ignoreChangesAndAdditions, ignoreDeletions bool) (map[string]interface{}, error) {
 | 
				
			||||||
	originalIndex, modifiedIndex := 0, 0
 | 
						originalIndex, modifiedIndex := 0, 0
 | 
				
			||||||
	patch := map[string]interface{}{}
 | 
						patch := map[string]interface{}{}
 | 
				
			||||||
	patch[directiveMarker] = mergePrimitivesListDirective
 | 
						patch[directiveMarker] = MergePrimitivesListDirective
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for originalIndex < len(originalScalars) && modifiedIndex < len(modifiedScalars) {
 | 
						for originalIndex < len(originalScalars) && modifiedIndex < len(modifiedScalars) {
 | 
				
			||||||
		originalString := fmt.Sprintf("%v", originalScalars[originalIndex])
 | 
							originalString := fmt.Sprintf("%v", originalScalars[originalIndex])
 | 
				
			||||||
@@ -627,7 +627,7 @@ func mergeMap(original, patch map[string]interface{}, t reflect.Type) (map[strin
 | 
				
			|||||||
			return map[string]interface{}{}, nil
 | 
								return map[string]interface{}{}, nil
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if v == mergePrimitivesListDirective {
 | 
							if v == MergePrimitivesListDirective {
 | 
				
			||||||
			// delete the directiveMarker's key-value pair to avoid delta map and delete map
 | 
								// delete the directiveMarker's key-value pair to avoid delta map and delete map
 | 
				
			||||||
			// overlaping with each other when calculating a ThreeWayDiff for list of Primitives.
 | 
								// overlaping with each other when calculating a ThreeWayDiff for list of Primitives.
 | 
				
			||||||
			// Otherwise, the overlaping will cause it calling LookupPatchMetadata() which will
 | 
								// Otherwise, the overlaping will cause it calling LookupPatchMetadata() which will
 | 
				
			||||||
@@ -718,7 +718,7 @@ func mergeMap(original, patch map[string]interface{}, t reflect.Type) (map[strin
 | 
				
			|||||||
// the patch because getting a deep copy of a slice in golang is highly
 | 
					// the patch because getting a deep copy of a slice in golang is highly
 | 
				
			||||||
// non-trivial.
 | 
					// non-trivial.
 | 
				
			||||||
// The patch could be a map[string]interface{} representing a slice of primitives.
 | 
					// The patch could be a map[string]interface{} representing a slice of primitives.
 | 
				
			||||||
// If the patch map doesn't has the specific directiveMarker (mergePrimitivesListDirective),
 | 
					// If the patch map doesn't has the specific directiveMarker (MergePrimitivesListDirective),
 | 
				
			||||||
// it returns an error. Please check patch_test.go and find the test case named
 | 
					// it returns an error. Please check patch_test.go and find the test case named
 | 
				
			||||||
// "merge lists of scalars for list of primitives" to see what the patch looks like.
 | 
					// "merge lists of scalars for list of primitives" to see what the patch looks like.
 | 
				
			||||||
// Patch is still []interface{} for all the other types.
 | 
					// Patch is still []interface{} for all the other types.
 | 
				
			||||||
@@ -731,7 +731,7 @@ func mergeSlice(original []interface{}, patch interface{}, elemType reflect.Type
 | 
				
			|||||||
	if patchMap, ok := patch.(map[string]interface{}); ok {
 | 
						if patchMap, ok := patch.(map[string]interface{}); ok {
 | 
				
			||||||
		// We try to merge the original slice with a patch map only when the map has
 | 
							// We try to merge the original slice with a patch map only when the map has
 | 
				
			||||||
		// a specific directiveMarker. Otherwise, this patch will be treated as invalid.
 | 
							// a specific directiveMarker. Otherwise, this patch will be treated as invalid.
 | 
				
			||||||
		if directiveValue, ok := patchMap[directiveMarker]; ok && directiveValue == mergePrimitivesListDirective {
 | 
							if directiveValue, ok := patchMap[directiveMarker]; ok && directiveValue == MergePrimitivesListDirective {
 | 
				
			||||||
			return mergeSliceOfScalarsWithPatchMap(original, patchMap)
 | 
								return mergeSliceOfScalarsWithPatchMap(original, patchMap)
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			return nil, fmt.Errorf("Unable to merge a slice with an invalid map")
 | 
								return nil, fmt.Errorf("Unable to merge a slice with an invalid map")
 | 
				
			||||||
@@ -838,10 +838,10 @@ func mergeSlice(original []interface{}, patch interface{}, elemType reflect.Type
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// mergeSliceOfScalarsWithPatchMap merges the original slice with a patch map and
 | 
					// mergeSliceOfScalarsWithPatchMap merges the original slice with a patch map and
 | 
				
			||||||
// returns an uniqified and sorted slice of primitives.
 | 
					// returns an uniqified and sorted slice of primitives.
 | 
				
			||||||
// The patch map must have the specific directiveMarker (mergePrimitivesListDirective).
 | 
					// The patch map must have the specific directiveMarker (MergePrimitivesListDirective).
 | 
				
			||||||
func mergeSliceOfScalarsWithPatchMap(original []interface{}, patch map[string]interface{}) ([]interface{}, error) {
 | 
					func mergeSliceOfScalarsWithPatchMap(original []interface{}, patch map[string]interface{}) ([]interface{}, error) {
 | 
				
			||||||
	// make sure the patch has the specific directiveMarker ()
 | 
						// make sure the patch has the specific directiveMarker ()
 | 
				
			||||||
	if directiveValue, ok := patch[directiveMarker]; ok && directiveValue != mergePrimitivesListDirective {
 | 
						if directiveValue, ok := patch[directiveMarker]; ok && directiveValue != MergePrimitivesListDirective {
 | 
				
			||||||
		return nil, fmt.Errorf("Unable to merge a slice with an invalid map")
 | 
							return nil, fmt.Errorf("Unable to merge a slice with an invalid map")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	delete(patch, directiveMarker)
 | 
						delete(patch, directiveMarker)
 | 
				
			||||||
@@ -1181,7 +1181,7 @@ func mergingMapFieldsHaveConflicts(
 | 
				
			|||||||
					return true, nil
 | 
										return true, nil
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				if leftMarker == mergePrimitivesListDirective && rightMarker == mergePrimitivesListDirective {
 | 
									if leftMarker == MergePrimitivesListDirective && rightMarker == MergePrimitivesListDirective {
 | 
				
			||||||
					return false, nil
 | 
										return false, nil
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -1209,7 +1209,7 @@ func mapsHaveConflicts(typedLeft, typedRight map[string]interface{}, structType
 | 
				
			|||||||
	isForListOfPrimitives := false
 | 
						isForListOfPrimitives := false
 | 
				
			||||||
	if leftDirective, ok := typedLeft[directiveMarker]; ok {
 | 
						if leftDirective, ok := typedLeft[directiveMarker]; ok {
 | 
				
			||||||
		if rightDirective, ok := typedRight[directiveMarker]; ok {
 | 
							if rightDirective, ok := typedRight[directiveMarker]; ok {
 | 
				
			||||||
			if leftDirective == mergePrimitivesListDirective && rightDirective == rightDirective {
 | 
								if leftDirective == MergePrimitivesListDirective && rightDirective == rightDirective {
 | 
				
			||||||
				isForListOfPrimitives = true
 | 
									isForListOfPrimitives = true
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								test/fixtures/pkg/kubectl/cmd/apply/rc.yaml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								test/fixtures/pkg/kubectl/cmd/apply/rc.yaml
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,8 @@
 | 
				
			|||||||
apiVersion: v1
 | 
					apiVersion: v1
 | 
				
			||||||
kind: ReplicationController
 | 
					kind: ReplicationController
 | 
				
			||||||
metadata:
 | 
					metadata:
 | 
				
			||||||
 | 
					  finalizers:
 | 
				
			||||||
 | 
					  - b/b
 | 
				
			||||||
  name: test-rc
 | 
					  name: test-rc
 | 
				
			||||||
  labels:
 | 
					  labels:
 | 
				
			||||||
    name: test-rc
 | 
					    name: test-rc
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user