diff --git a/pkg/kubectl/cmd/BUILD b/pkg/kubectl/cmd/BUILD index 390a91eb28d..edb6fd67641 100644 --- a/pkg/kubectl/cmd/BUILD +++ b/pkg/kubectl/cmd/BUILD @@ -150,6 +150,7 @@ go_test( "delete_test.go", "describe_test.go", "drain_test.go", + "edit_test.go", "exec_test.go", "expose_test.go", "get_test.go", @@ -166,6 +167,7 @@ go_test( "top_test.go", ], data = [ + "testdata", "//examples:config", "//test/fixtures", ], @@ -191,6 +193,7 @@ go_test( "//pkg/util/term:go_default_library", "//vendor:github.com/spf13/cobra", "//vendor:github.com/stretchr/testify/assert", + "//vendor:gopkg.in/yaml.v2", "//vendor:k8s.io/apimachinery/pkg/api/equality", "//vendor:k8s.io/apimachinery/pkg/api/errors", "//vendor:k8s.io/apimachinery/pkg/api/meta", @@ -201,7 +204,9 @@ go_test( "//vendor:k8s.io/apimachinery/pkg/runtime/serializer/json", "//vendor:k8s.io/apimachinery/pkg/runtime/serializer/streaming", "//vendor:k8s.io/apimachinery/pkg/types", + "//vendor:k8s.io/apimachinery/pkg/util/diff", "//vendor:k8s.io/apimachinery/pkg/util/intstr", + "//vendor:k8s.io/apimachinery/pkg/util/sets", "//vendor:k8s.io/apimachinery/pkg/util/strategicpatch", "//vendor:k8s.io/apimachinery/pkg/util/wait", "//vendor:k8s.io/apimachinery/pkg/watch", @@ -228,6 +233,7 @@ filegroup( "//pkg/kubectl/cmd/rollout:all-srcs", "//pkg/kubectl/cmd/set:all-srcs", "//pkg/kubectl/cmd/templates:all-srcs", + "//pkg/kubectl/cmd/testdata/edit:all-srcs", "//pkg/kubectl/cmd/testing:all-srcs", "//pkg/kubectl/cmd/util:all-srcs", ], diff --git a/pkg/kubectl/cmd/edit.go b/pkg/kubectl/cmd/edit.go index 3aeaa87c1d2..69d92c4d23c 100644 --- a/pkg/kubectl/cmd/edit.go +++ b/pkg/kubectl/cmd/edit.go @@ -240,7 +240,7 @@ func runEdit(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args file: file, } containsError = true - fmt.Fprintln(out, results.addError(errors.NewInvalid(api.Kind(""), "", field.ErrorList{field.Invalid(nil, "The edited file failed validation", fmt.Sprintf("%v", err))}), infos[0])) + fmt.Fprintln(errOut, results.addError(errors.NewInvalid(api.Kind(""), "", field.ErrorList{field.Invalid(nil, "The edited file failed validation", fmt.Sprintf("%v", err))}), infos[0])) continue } @@ -505,7 +505,7 @@ func visitToPatch( results.version = defaultVersion patched, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, types.StrategicMergePatchType, patch) if err != nil { - fmt.Fprintln(out, results.addError(err, info)) + fmt.Fprintln(errOut, results.addError(err, info)) return nil } info.Refresh(patched, true) diff --git a/pkg/kubectl/cmd/edit_test.go b/pkg/kubectl/cmd/edit_test.go new file mode 100644 index 00000000000..d348d00fba1 --- /dev/null +++ b/pkg/kubectl/cmd/edit_test.go @@ -0,0 +1,281 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cmd + +import ( + "bytes" + "encoding/json" + "io" + "io/ioutil" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/spf13/cobra" + + yaml "gopkg.in/yaml.v2" + + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/util/diff" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/client-go/rest/fake" + "k8s.io/kubernetes/pkg/api" + cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" + cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" + "k8s.io/kubernetes/pkg/kubectl/resource" +) + +type EditTestCase struct { + Description string `yaml:"description"` + // create or edit + Mode string `yaml:"mode"` + Args []string `yaml:"args"` + Filename string `yaml:"filename"` + Output string `yaml:"outputFormat"` + Namespace string `yaml:"namespace"` + ExpectedStdout []string `yaml:"expectedStdout"` + ExpectedStderr []string `yaml:"expectedStderr"` + ExpectedExitCode int `yaml:"expectedExitCode"` + + Steps []EditStep `yaml:"steps"` +} + +type EditStep struct { + // edit or request + StepType string `yaml:"type"` + + // only applies to request + RequestMethod string `yaml:"expectedMethod,omitempty"` + RequestPath string `yaml:"expectedPath,omitempty"` + RequestContentType string `yaml:"expectedContentType,omitempty"` + Input string `yaml:"expectedInput"` + + // only applies to request + ResponseStatusCode int `yaml:"resultingStatusCode,omitempty"` + + Output string `yaml:"resultingOutput"` +} + +func TestEdit(t *testing.T) { + var ( + name string + testcase EditTestCase + i int + err error + ) + + const updateEnvVar = "UPDATE_EDIT_FIXTURE_DATA" + updateInputFixtures := os.Getenv(updateEnvVar) == "true" + + reqResp := func(req *http.Request) (*http.Response, error) { + defer func() { i++ }() + if i > len(testcase.Steps)-1 { + t.Fatalf("%s, step %d: more requests than steps, got %s %s", name, i, req.Method, req.URL.Path) + } + step := testcase.Steps[i] + + body := []byte{} + if req.Body != nil { + body, err = ioutil.ReadAll(req.Body) + if err != nil { + t.Fatalf("%s, step %d: %v", name, i, err) + } + } + + inputFile := filepath.Join("testdata/edit", "testcase-"+name, step.Input) + expectedInput, err := ioutil.ReadFile(inputFile) + if err != nil { + t.Fatalf("%s, step %d: %v", name, i, err) + } + + outputFile := filepath.Join("testdata/edit", "testcase-"+name, step.Output) + resultingOutput, err := ioutil.ReadFile(outputFile) + if err != nil { + t.Fatalf("%s, step %d: %v", name, i, err) + } + + if req.Method == "POST" && req.URL.Path == "/callback" { + if step.StepType != "edit" { + t.Fatalf("%s, step %d: expected edit step, got %s %s", name, i, req.Method, req.URL.Path) + } + if bytes.Compare(body, expectedInput) != 0 { + if updateInputFixtures { + // Convenience to allow recapturing the input and persisting it here + ioutil.WriteFile(inputFile, body, os.FileMode(0644)) + } else { + t.Errorf("%s, step %d: diff in edit content:\n%s", name, i, diff.StringDiff(string(body), string(expectedInput))) + t.Logf("If the change in input is expected, rerun tests with %s=true to update input fixtures", updateEnvVar) + } + } + return &http.Response{StatusCode: 200, Body: ioutil.NopCloser(bytes.NewReader(resultingOutput))}, nil + } else { + if step.StepType != "request" { + t.Fatalf("%s, step %d: expected request step, got %s %s", name, i, req.Method, req.URL.Path) + } + body = tryIndent(body) + expectedInput = tryIndent(expectedInput) + if req.Method != step.RequestMethod || req.URL.Path != step.RequestPath || req.Header.Get("Content-Type") != step.RequestContentType { + t.Fatalf( + "%s, step %d: expected \n%s %s (content-type=%s)\ngot\n%s %s (content-type=%s)", name, i, + step.RequestMethod, step.RequestPath, step.RequestContentType, + req.Method, req.URL.Path, req.Header.Get("Content-Type"), + ) + } + if bytes.Compare(body, expectedInput) != 0 { + if updateInputFixtures { + // Convenience to allow recapturing the input and persisting it here + ioutil.WriteFile(inputFile, body, os.FileMode(0644)) + } else { + t.Errorf("%s, step %d: diff in edit content:\n%s", name, i, diff.StringDiff(string(body), string(expectedInput))) + t.Logf("If the change in input is expected, rerun tests with %s=true to update input fixtures", updateEnvVar) + } + } + return &http.Response{StatusCode: step.ResponseStatusCode, Header: defaultHeader(), Body: ioutil.NopCloser(bytes.NewReader(resultingOutput))}, nil + } + } + + handler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + resp, _ := reqResp(req) + for k, vs := range resp.Header { + w.Header().Del(k) + for _, v := range vs { + w.Header().Add(k, v) + } + } + w.WriteHeader(resp.StatusCode) + io.Copy(w, resp.Body) + }) + + server := httptest.NewServer(handler) + defer server.Close() + + os.Setenv("KUBE_EDITOR", "testdata/edit/test_editor.sh") + os.Setenv("KUBE_EDITOR_CALLBACK", server.URL+"/callback") + + testcases := sets.NewString() + filepath.Walk("testdata/edit", func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if path == "testdata/edit" { + return nil + } + name := filepath.Base(path) + if info.IsDir() { + if strings.HasPrefix(name, "testcase-") { + testcases.Insert(strings.TrimPrefix(name, "testcase-")) + } + return filepath.SkipDir + } + return nil + }) + // sanity check that we found the right folder + if !testcases.Has("create-list") { + t.Fatalf("Error locating edit testcases") + } + + for _, testcaseName := range testcases.List() { + t.Logf("Running testcase: %s", testcaseName) + i = 0 + name = testcaseName + testcase = EditTestCase{} + testcaseDir := filepath.Join("testdata", "edit", "testcase-"+name) + testcaseData, err := ioutil.ReadFile(filepath.Join(testcaseDir, "test.yaml")) + if err != nil { + t.Fatalf("%s: %v", name, err) + } + if err := yaml.Unmarshal(testcaseData, &testcase); err != nil { + t.Fatalf("%s: %v", name, err) + } + + f, tf, _, ns := cmdtesting.NewAPIFactory() + tf.Printer = &testPrinter{} + tf.ClientForMappingFunc = func(mapping *meta.RESTMapping) (resource.RESTClient, error) { + versionedAPIPath := "" + if mapping.GroupVersionKind.Group == "" { + versionedAPIPath = "/api/" + mapping.GroupVersionKind.Version + } else { + versionedAPIPath = "/apis/" + mapping.GroupVersionKind.Group + "/" + mapping.GroupVersionKind.Version + } + return &fake.RESTClient{ + APIRegistry: api.Registry, + VersionedAPIPath: versionedAPIPath, + NegotiatedSerializer: ns, //unstructuredSerializer, + Client: fake.CreateHTTPClient(reqResp), + }, nil + } + + if len(testcase.Namespace) > 0 { + tf.Namespace = testcase.Namespace + } + tf.ClientConfig = defaultClientConfig() + buf := bytes.NewBuffer([]byte{}) + errBuf := bytes.NewBuffer([]byte{}) + + var cmd *cobra.Command + switch testcase.Mode { + case "edit": + cmd = NewCmdEdit(f, buf, errBuf) + case "create": + cmd = NewCmdCreate(f, buf, errBuf) + cmd.Flags().Set("edit", "true") + default: + t.Errorf("%s: unexpected mode %s", name, testcase.Mode) + continue + } + if len(testcase.Filename) > 0 { + cmd.Flags().Set("filename", filepath.Join(testcaseDir, testcase.Filename)) + } + if len(testcase.Output) > 0 { + cmd.Flags().Set("output", testcase.Output) + } + + cmdutil.BehaviorOnFatal(func(str string, code int) { + errBuf.WriteString(str) + if testcase.ExpectedExitCode != code { + t.Errorf("%s: expected exit code %d, got %d: %s", name, testcase.ExpectedExitCode, code, str) + } + }) + + cmd.Run(cmd, testcase.Args) + + stdout := buf.String() + stderr := errBuf.String() + + for _, s := range testcase.ExpectedStdout { + if !strings.Contains(stdout, s) { + t.Errorf("%s: expected to see '%s' in stdout\n\nstdout:\n%s\n\nstderr:\n%s", name, s, stdout, stderr) + } + } + for _, s := range testcase.ExpectedStderr { + if !strings.Contains(stderr, s) { + t.Errorf("%s: expected to see '%s' in stderr\n\nstdout:\n%s\n\nstderr:\n%s", name, s, stdout, stderr) + } + } + } +} + +func tryIndent(data []byte) []byte { + indented := &bytes.Buffer{} + if err := json.Indent(indented, data, "", "\t"); err == nil { + return indented.Bytes() + } + return data +} diff --git a/pkg/kubectl/cmd/testdata/edit/BUILD b/pkg/kubectl/cmd/testdata/edit/BUILD new file mode 100644 index 00000000000..48bb09eaaa4 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/BUILD @@ -0,0 +1,35 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_binary", + "go_library", +) + +go_binary( + name = "edit", + library = ":go_default_library", + tags = ["automanaged"], +) + +go_library( + name = "go_default_library", + srcs = ["record.go"], + tags = ["automanaged"], + deps = ["//vendor:gopkg.in/yaml.v2"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) diff --git a/pkg/kubectl/cmd/testdata/edit/README b/pkg/kubectl/cmd/testdata/edit/README new file mode 100644 index 00000000000..eb72b9271c6 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/README @@ -0,0 +1,22 @@ +This folder contains test cases for interactive edit, and helpers for recording new test cases + +To record a new test: + +1. Start a local cluster running unsecured on http://localhost:8080 (e.g. hack/local-up-cluster.sh) +2. Set up any pre-existing resources you want to be available on that server (namespaces, resources to edit, etc) +3. Run ./pkg/kubectl/cmd/testdata/edit/record_testcase.sh my-testcase +4. Run the desired `kubectl edit ...` command, and interact with the editor as desired until it completes. + * You can do things that cause errors to appear in the editor (change immutable fields, fail validation, etc) + * You can perform edit flows that invoke the editor multiple times + * You can make out-of-band changes to the server resources that cause conflict errors to be returned + * The API requests/responses and editor inputs/outputs are captured in your testcase folder +5. Type exit. +6. Inspect the captured requests/responses and inputs/outputs for sanity +7. Modify the generated test.yaml file: + * Set a description of what the test is doing + * Enter the args (if any) you invoked edit with + * Enter the filename (if any) you invoked edit with + * Enter the output format (if any) you invoked edit with + * Optionally specify substrings to look for in the stdout or stderr of the edit command +8. Add your new testcase name to the list of testcases in edit_test.go +9. Run `go test ./pkg/kubectl/cmd -run TestEdit -v` to run edit tests diff --git a/pkg/kubectl/cmd/testdata/edit/record.go b/pkg/kubectl/cmd/testdata/edit/record.go new file mode 100644 index 00000000000..95f15c64a13 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/record.go @@ -0,0 +1,169 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "os" + "strings" + + yaml "gopkg.in/yaml.v2" +) + +type EditTestCase struct { + Description string `yaml:"description"` + // create or edit + Mode string `yaml:"mode"` + Args []string `yaml:"args"` + Filename string `yaml:"filename"` + Output string `yaml:"outputFormat"` + Namespace string `yaml:"namespace"` + ExpectedStdout []string `yaml:"expectedStdout"` + ExpectedStderr []string `yaml:"expectedStderr"` + ExpectedExitCode int `yaml:"expectedExitCode"` + + Steps []EditStep `yaml:"steps"` +} + +type EditStep struct { + // edit or request + StepType string `yaml:"type"` + + // only applies to request + RequestMethod string `yaml:"expectedMethod,omitempty"` + RequestPath string `yaml:"expectedPath,omitempty"` + RequestContentType string `yaml:"expectedContentType,omitempty"` + Input string `yaml:"expectedInput"` + + // only applies to request + ResponseStatusCode int `yaml:"resultingStatusCode,omitempty"` + + Output string `yaml:"resultingOutput"` +} + +func main() { + tc := &EditTestCase{ + Description: "add a testcase description", + Mode: "edit", + Args: []string{"set", "args"}, + ExpectedStdout: []string{"expected stdout substring"}, + ExpectedStderr: []string{"expected stderr substring"}, + } + + var currentStep *EditStep + + fmt.Println(http.ListenAndServe(":8081", http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + + // Record non-discovery things + record := false + switch segments := strings.Split(strings.Trim(req.URL.Path, "/"), "/"); segments[0] { + case "api": + // api, version + record = len(segments) > 2 + case "apis": + // apis, group, version + record = len(segments) > 3 + case "callback": + record = true + } + + body, err := ioutil.ReadAll(req.Body) + checkErr(err) + + switch m, p := req.Method, req.URL.Path; { + case m == "POST" && p == "/callback/in": + if currentStep != nil { + panic("cannot post input with step already in progress") + } + filename := fmt.Sprintf("%d.original", len(tc.Steps)) + checkErr(ioutil.WriteFile(filename, body, os.FileMode(0755))) + currentStep = &EditStep{StepType: "edit", Input: filename} + case m == "POST" && p == "/callback/out": + if currentStep == nil || currentStep.StepType != "edit" { + panic("cannot post output without posting input first") + } + filename := fmt.Sprintf("%d.edited", len(tc.Steps)) + checkErr(ioutil.WriteFile(filename, body, os.FileMode(0755))) + currentStep.Output = filename + tc.Steps = append(tc.Steps, *currentStep) + currentStep = nil + default: + if currentStep != nil { + panic("cannot make request with step already in progress") + } + + urlCopy := *req.URL + urlCopy.Host = "localhost:8080" + urlCopy.Scheme = "http" + proxiedReq, err := http.NewRequest(req.Method, urlCopy.String(), bytes.NewReader(body)) + checkErr(err) + proxiedReq.Header = req.Header + resp, err := http.DefaultClient.Do(proxiedReq) + checkErr(err) + defer resp.Body.Close() + + bodyOut, err := ioutil.ReadAll(resp.Body) + checkErr(err) + + for k, vs := range resp.Header { + for _, v := range vs { + w.Header().Add(k, v) + } + } + w.WriteHeader(resp.StatusCode) + w.Write(bodyOut) + + if record { + infile := fmt.Sprintf("%d.request", len(tc.Steps)) + outfile := fmt.Sprintf("%d.response", len(tc.Steps)) + checkErr(ioutil.WriteFile(infile, tryIndent(body), os.FileMode(0755))) + checkErr(ioutil.WriteFile(outfile, tryIndent(bodyOut), os.FileMode(0755))) + tc.Steps = append(tc.Steps, EditStep{ + StepType: "request", + Input: infile, + Output: outfile, + RequestContentType: req.Header.Get("Content-Type"), + RequestMethod: req.Method, + RequestPath: req.URL.Path, + ResponseStatusCode: resp.StatusCode, + }) + } + } + + tcData, err := yaml.Marshal(tc) + checkErr(err) + checkErr(ioutil.WriteFile("test.yaml", tcData, os.FileMode(0755))) + }))) +} + +func checkErr(err error) { + if err != nil { + panic(err) + } +} + +func tryIndent(data []byte) []byte { + indented := &bytes.Buffer{} + if err := json.Indent(indented, data, "", "\t"); err == nil { + return indented.Bytes() + } + return data +} diff --git a/pkg/kubectl/cmd/testdata/edit/record_editor.sh b/pkg/kubectl/cmd/testdata/edit/record_editor.sh new file mode 100755 index 00000000000..0a7d4c376ea --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/record_editor.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Copyright 2017 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +# send the original content to the server +curl -s -k -XPOST "http://localhost:8081/callback/in" --data-binary "@${1}" +# allow the user to edit the file +vi "${1}" +# send the resulting content to the server +curl -s -k -XPOST "http://localhost:8081/callback/out" --data-binary "@${1}" diff --git a/pkg/kubectl/cmd/testdata/edit/record_testcase.sh b/pkg/kubectl/cmd/testdata/edit/record_testcase.sh new file mode 100755 index 00000000000..9a51c351c66 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/record_testcase.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +# Copyright 2017 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +if [[ -z "${1-}" ]]; then + echo "Usage: record_testcase.sh testcase-name" + exit 1 +fi + +# Clean up the test server +function cleanup { + if [[ ! -z "${pid-}" ]]; then + echo "Stopping recording server (${pid})" + # kill the process `go run` launched + pkill -P "${pid}" + # kill the `go run` process itself + kill -9 "${pid}" + fi +} + +testcase="${1}" + +test_root="$(dirname "${BASH_SOURCE}")" +testcase_dir="${test_root}/testcase-${testcase}" +mkdir -p "${testcase_dir}" + +pushd "${testcase_dir}" + export EDITOR="../record_editor.sh" + go run "../record.go" & + pid=$! + trap cleanup EXIT + echo "Started recording server (${pid})" + + # Make a kubeconfig that makes kubectl talk to our test server + edit_kubeconfig="${TMP:-/tmp}/edit_test.kubeconfig" + echo "apiVersion: v1 +clusters: +- cluster: + server: http://localhost:8081 + name: test +contexts: +- context: + cluster: test + user: test + name: test +current-context: test +kind: Config +users: [] +" > "${edit_kubeconfig}" + export KUBECONFIG="${edit_kubeconfig}" + + echo "Starting subshell. Type exit when finished." + bash +popd diff --git a/pkg/kubectl/cmd/testdata/edit/test_editor.sh b/pkg/kubectl/cmd/testdata/edit/test_editor.sh new file mode 100755 index 00000000000..268a8078c2a --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/test_editor.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# Copyright 2017 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -o errexit +set -o nounset +set -o pipefail + +# Send the file content to the server +if command -v curl &>/dev/null; then + curl -s -k -XPOST --data-binary "@${1}" -o "${1}.result" "${KUBE_EDITOR_CALLBACK}" +elif command -v wget &>/dev/null; then + wget --post-file="${1}" -O "${1}.result" "${KUBE_EDITOR_CALLBACK}" +else + echo "curl and wget are unavailable" >&2 + exit 1 +fi + +# Use the response as the edited version +mv "${1}.result" "${1}" diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/0.edited b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/0.edited new file mode 100755 index 00000000000..47a003047f9 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/0.edited @@ -0,0 +1,28 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: 2017-02-03T06:44:47Z + labels: + app: svc1modified + name: svc1 + namespace: edit-test + resourceVersion: "2942" + selfLink: /api/v1/namespaces/edit-test/services/svc1 + uid: 4149f70e-e9dc-11e6-8c3b-acbc32c1ca87 +spec: + clusterIP: 10.0.0.118 + ports: + - name: "81" + port: 82 + protocol: TCP + targetPort: 81 + selector: + app: svc1 + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/0.original b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/0.original new file mode 100755 index 00000000000..b69c7dca8b7 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/0.original @@ -0,0 +1,28 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: 2017-02-03T06:44:47Z + labels: + app: svc1 + name: svc1 + namespace: edit-test + resourceVersion: "2942" + selfLink: /api/v1/namespaces/edit-test/services/svc1 + uid: 4149f70e-e9dc-11e6-8c3b-acbc32c1ca87 +spec: + clusterIP: 10.0.0.118 + ports: + - name: "81" + port: 81 + protocol: TCP + targetPort: 81 + selector: + app: svc1 + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/1.request b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/1.request new file mode 100755 index 00000000000..ce3eabeccc8 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/1.request @@ -0,0 +1,33 @@ +{ + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "svc1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/services/svc1", + "uid": "4149f70e-e9dc-11e6-8c3b-acbc32c1ca87", + "creationTimestamp": "2017-02-03T06:44:47Z", + "labels": { + "app": "svc1modified" + } + }, + "spec": { + "ports": [ + { + "name": "81", + "protocol": "TCP", + "port": 82, + "targetPort": 81 + } + ], + "selector": { + "app": "svc1" + }, + "clusterIP": "10.0.0.118", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/1.response b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/1.response new file mode 100755 index 00000000000..61a0dea6405 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/1.response @@ -0,0 +1,34 @@ +{ + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "svc1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/services/svc1", + "uid": "c07152b8-e9dc-11e6-8c3b-acbc32c1ca87", + "resourceVersion": "3171", + "creationTimestamp": "2017-02-03T06:48:21Z", + "labels": { + "app": "svc1modified" + } + }, + "spec": { + "ports": [ + { + "name": "81", + "protocol": "TCP", + "port": 82, + "targetPort": 81 + } + ], + "selector": { + "app": "svc1" + }, + "clusterIP": "10.0.0.118", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/2.edited b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/2.edited new file mode 100755 index 00000000000..e764b13a65b --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/2.edited @@ -0,0 +1,28 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: 2017-02-03T06:44:43Z + labels: + app: svc2modified + name: svc2 + namespace: edit-test + resourceVersion: "2936" + selfLink: /api/v1/namespaces/edit-test/services/svc2 + uid: 3e9b10db-e9dc-11e6-8c3b-acbc32c1ca87 +spec: + clusterIP: 10.0.0.182.1 + ports: + - name: "80" + port: 80 + protocol: VHF + targetPort: 80 + selector: + app: svc2 + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/2.original b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/2.original new file mode 100755 index 00000000000..9c74ec36314 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/2.original @@ -0,0 +1,28 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: 2017-02-03T06:44:43Z + labels: + app: svc2 + name: svc2 + namespace: edit-test + resourceVersion: "2936" + selfLink: /api/v1/namespaces/edit-test/services/svc2 + uid: 3e9b10db-e9dc-11e6-8c3b-acbc32c1ca87 +spec: + clusterIP: 10.0.0.182 + ports: + - name: "80" + port: 80 + protocol: TCP + targetPort: 80 + selector: + app: svc2 + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/3.request b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/3.request new file mode 100755 index 00000000000..38cee1a5684 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/3.request @@ -0,0 +1,33 @@ +{ + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "svc2", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/services/svc2", + "uid": "3e9b10db-e9dc-11e6-8c3b-acbc32c1ca87", + "creationTimestamp": "2017-02-03T06:44:43Z", + "labels": { + "app": "svc2modified" + } + }, + "spec": { + "ports": [ + { + "name": "80", + "protocol": "VHF", + "port": 80, + "targetPort": 80 + } + ], + "selector": { + "app": "svc2" + }, + "clusterIP": "10.0.0.182.1", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/3.response b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/3.response new file mode 100755 index 00000000000..156f2ea1314 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/3.response @@ -0,0 +1,25 @@ +{ + "kind": "Status", + "apiVersion": "v1", + "metadata": {}, + "status": "Failure", + "message": "Service \"svc2\" is invalid: [spec.ports[0].protocol: Unsupported value: \"VHF\": supported values: TCP, UDP, spec.clusterIP: Invalid value: \"10.0.0.182.1\": must be empty, 'None', or a valid IP address]", + "reason": "Invalid", + "details": { + "name": "svc2", + "kind": "Service", + "causes": [ + { + "reason": "FieldValueNotSupported", + "message": "Unsupported value: \"VHF\": supported values: TCP, UDP", + "field": "spec.ports[0].protocol" + }, + { + "reason": "FieldValueInvalid", + "message": "Invalid value: \"10.0.0.182.1\": must be empty, 'None', or a valid IP address", + "field": "spec.clusterIP" + } + ] + }, + "code": 422 +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/svc.yaml b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/svc.yaml new file mode 100644 index 00000000000..74e83157b0f --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/svc.yaml @@ -0,0 +1,54 @@ +apiVersion: v1 +items: +- apiVersion: v1 + kind: Service + metadata: + creationTimestamp: 2017-02-03T06:44:47Z + labels: + app: svc1 + name: svc1 + namespace: edit-test + resourceVersion: "2942" + selfLink: /api/v1/namespaces/edit-test/services/svc1 + uid: 4149f70e-e9dc-11e6-8c3b-acbc32c1ca87 + spec: + clusterIP: 10.0.0.118 + ports: + - name: "81" + port: 81 + protocol: TCP + targetPort: 81 + selector: + app: svc1 + sessionAffinity: None + type: ClusterIP + status: + loadBalancer: {} +- apiVersion: v1 + kind: Service + metadata: + creationTimestamp: 2017-02-03T06:44:43Z + labels: + app: svc2 + name: svc2 + namespace: edit-test + resourceVersion: "2936" + selfLink: /api/v1/namespaces/edit-test/services/svc2 + uid: 3e9b10db-e9dc-11e6-8c3b-acbc32c1ca87 + spec: + clusterIP: 10.0.0.182 + ports: + - name: "80" + port: 80 + protocol: TCP + targetPort: 80 + selector: + app: svc2 + sessionAffinity: None + type: ClusterIP + status: + loadBalancer: {} +kind: List +metadata: {} +resourceVersion: "" +selfLink: "" diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/test.yaml b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/test.yaml new file mode 100755 index 00000000000..5663b94d919 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list-error/test.yaml @@ -0,0 +1,30 @@ +description: create list with errors +mode: create +filename: "svc.yaml" +namespace: "edit-test" +expectedStdout: +- "service \"svc1\" created" +expectedStderr: +- "\"svc2\" is invalid" +expectedExitCode: 1 +steps: +- type: edit + expectedInput: 0.original + resultingOutput: 0.edited +- type: request + expectedMethod: POST + expectedPath: /api/v1/namespaces/edit-test/services + expectedContentType: application/json + expectedInput: 1.request + resultingStatusCode: 201 + resultingOutput: 1.response +- type: edit + expectedInput: 2.original + resultingOutput: 2.edited +- type: request + expectedMethod: POST + expectedPath: /api/v1/namespaces/edit-test/services + expectedContentType: application/json + expectedInput: 3.request + resultingStatusCode: 422 + resultingOutput: 3.response diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list/0.edited b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/0.edited new file mode 100755 index 00000000000..5781d6c0101 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/0.edited @@ -0,0 +1,22 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +kind: Service +metadata: + labels: + app: svc1 + new-label: new-value + name: svc1 + namespace: edit-test +spec: + ports: + - name: "81" + port: 82 + protocol: TCP + targetPort: 81 + selector: + app: svc1 + sessionAffinity: None + type: ClusterIP diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list/0.original b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/0.original new file mode 100755 index 00000000000..d1db48e5a54 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/0.original @@ -0,0 +1,21 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +kind: Service +metadata: + labels: + app: svc1 + name: svc1 + namespace: edit-test +spec: + ports: + - name: "81" + port: 81 + protocol: TCP + targetPort: 81 + selector: + app: svc1 + sessionAffinity: None + type: ClusterIP diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list/1.request b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/1.request new file mode 100755 index 00000000000..dde2695b53b --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/1.request @@ -0,0 +1,31 @@ +{ + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "svc1", + "namespace": "edit-test", + "creationTimestamp": null, + "labels": { + "app": "svc1", + "new-label": "new-value" + } + }, + "spec": { + "ports": [ + { + "name": "81", + "protocol": "TCP", + "port": 82, + "targetPort": 81 + } + ], + "selector": { + "app": "svc1" + }, + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list/1.response b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/1.response new file mode 100755 index 00000000000..46af7748a72 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/1.response @@ -0,0 +1,35 @@ +{ + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "svc1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/services/svc1", + "uid": "208b27ed-ea5b-11e6-9b42-acbc32c1ca87", + "resourceVersion": "1437", + "creationTimestamp": "2017-02-03T21:52:59Z", + "labels": { + "app": "svc1", + "new-label": "new-value" + } + }, + "spec": { + "ports": [ + { + "name": "81", + "protocol": "TCP", + "port": 82, + "targetPort": 81 + } + ], + "selector": { + "app": "svc1" + }, + "clusterIP": "10.0.0.15", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list/2.edited b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/2.edited new file mode 100755 index 00000000000..a93464e04b7 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/2.edited @@ -0,0 +1,22 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +kind: Service +metadata: + labels: + app: svc2 + name: svc2 + namespace: edit-test +spec: + ports: + - name: "80" + port: 80 + protocol: TCP + targetPort: 81 + selector: + app: svc2 + new-label: new-value + sessionAffinity: None + type: ClusterIP diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list/2.original b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/2.original new file mode 100755 index 00000000000..e47dc6ab03b --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/2.original @@ -0,0 +1,21 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +kind: Service +metadata: + labels: + app: svc2 + name: svc2 + namespace: edit-test +spec: + ports: + - name: "80" + port: 80 + protocol: TCP + targetPort: 80 + selector: + app: svc2 + sessionAffinity: None + type: ClusterIP diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list/3.request b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/3.request new file mode 100755 index 00000000000..9c71a88f4f0 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/3.request @@ -0,0 +1,31 @@ +{ + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "svc2", + "namespace": "edit-test", + "creationTimestamp": null, + "labels": { + "app": "svc2" + } + }, + "spec": { + "ports": [ + { + "name": "80", + "protocol": "TCP", + "port": 80, + "targetPort": 81 + } + ], + "selector": { + "app": "svc2", + "new-label": "new-value" + }, + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list/3.response b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/3.response new file mode 100755 index 00000000000..7cba8df77cc --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/3.response @@ -0,0 +1,35 @@ +{ + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "svc2", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/services/svc2", + "uid": "31a1b8ae-ea5b-11e6-9b42-acbc32c1ca87", + "resourceVersion": "1470", + "creationTimestamp": "2017-02-03T21:53:27Z", + "labels": { + "app": "svc2" + } + }, + "spec": { + "ports": [ + { + "name": "80", + "protocol": "TCP", + "port": 80, + "targetPort": 81 + } + ], + "selector": { + "app": "svc2", + "new-label": "new-value" + }, + "clusterIP": "10.0.0.55", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list/svc.yaml b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/svc.yaml new file mode 100644 index 00000000000..14ce81c8f74 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/svc.yaml @@ -0,0 +1,39 @@ +apiVersion: v1 +items: +- apiVersion: v1 + kind: Service + metadata: + labels: + app: svc1 + name: svc1 + spec: + ports: + - name: "81" + port: 81 + protocol: TCP + targetPort: 81 + selector: + app: svc1 + sessionAffinity: None + type: ClusterIP +- apiVersion: v1 + kind: Service + metadata: + labels: + app: svc2 + name: svc2 + namespace: edit-test + spec: + ports: + - name: "80" + port: 80 + protocol: TCP + targetPort: 80 + selector: + app: svc2 + sessionAffinity: None + type: ClusterIP +kind: List +metadata: {} +resourceVersion: "" +selfLink: "" diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-create-list/test.yaml b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/test.yaml new file mode 100755 index 00000000000..0b75c7ffe68 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-create-list/test.yaml @@ -0,0 +1,29 @@ +description: edit while creating from a list +mode: create +filename: "svc.yaml" +namespace: "edit-test" +expectedStdout: +- service "svc1" created +- service "svc2" created +expectedExitCode: 0 +steps: +- type: edit + expectedInput: 0.original + resultingOutput: 0.edited +- type: request + expectedMethod: POST + expectedPath: /api/v1/namespaces/edit-test/services + expectedContentType: application/json + expectedInput: 1.request + resultingStatusCode: 201 + resultingOutput: 1.response +- type: edit + expectedInput: 2.original + resultingOutput: 2.edited +- type: request + expectedMethod: POST + expectedPath: /api/v1/namespaces/edit-test/services + expectedContentType: application/json + expectedInput: 3.request + resultingStatusCode: 201 + resultingOutput: 3.response diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/0.request b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/0.request new file mode 100755 index 00000000000..e69de29bb2d diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/0.response b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/0.response new file mode 100755 index 00000000000..4fb08268eb3 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/0.response @@ -0,0 +1,35 @@ +{ + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "svc1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/services/svc1", + "uid": "5f7da8db-e8c3-11e6-b7e2-acbc32c1ca87", + "resourceVersion": "20820", + "creationTimestamp": "2017-02-01T21:14:09Z", + "labels": { + "app": "svc1", + "new-label": "new-value" + } + }, + "spec": { + "ports": [ + { + "name": "80", + "protocol": "TCP", + "port": 81, + "targetPort": 80 + } + ], + "selector": { + "app": "svc1" + }, + "clusterIP": "10.0.0.146", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/1.edited b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/1.edited new file mode 100755 index 00000000000..cd3f5b5682b --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/1.edited @@ -0,0 +1,29 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: 2017-02-01T21:14:09Z + labels: + app: svc1 + new-label: new-value + name: svc1 + namespace: edit-test + resourceVersion: "20820" + selfLink: /api/v1/namespaces/edit-test/services/svc1 + uid: 5f7da8db-e8c3-11e6-b7e2-acbc32c1ca87 +spec: + clusterIP: 10.0.0.146.1 + ports: + - name: "80" + port: 81 + protocol: TCP + targetPort: 80 + selector: + app: svc1 + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/1.original b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/1.original new file mode 100755 index 00000000000..5d72e9bb280 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/1.original @@ -0,0 +1,29 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: 2017-02-01T21:14:09Z + labels: + app: svc1 + new-label: new-value + name: svc1 + namespace: edit-test + resourceVersion: "20820" + selfLink: /api/v1/namespaces/edit-test/services/svc1 + uid: 5f7da8db-e8c3-11e6-b7e2-acbc32c1ca87 +spec: + clusterIP: 10.0.0.146 + ports: + - name: "80" + port: 81 + protocol: TCP + targetPort: 80 + selector: + app: svc1 + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/2.request b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/2.request new file mode 100755 index 00000000000..3697353228a --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/2.request @@ -0,0 +1,5 @@ +{ + "spec": { + "clusterIP": "10.0.0.146.1" + } +} \ No newline at end of file diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/2.response b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/2.response new file mode 100755 index 00000000000..436b9d9ff12 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/2.response @@ -0,0 +1,25 @@ +{ + "kind": "Status", + "apiVersion": "v1", + "metadata": {}, + "status": "Failure", + "message": "Service \"svc1\" is invalid: [spec.clusterIP: Invalid value: \"10.0.0.146.1\": field is immutable, spec.clusterIP: Invalid value: \"10.0.0.146.1\": must be empty, 'None', or a valid IP address]", + "reason": "Invalid", + "details": { + "name": "svc1", + "kind": "Service", + "causes": [ + { + "reason": "FieldValueInvalid", + "message": "Invalid value: \"10.0.0.146.1\": field is immutable", + "field": "spec.clusterIP" + }, + { + "reason": "FieldValueInvalid", + "message": "Invalid value: \"10.0.0.146.1\": must be empty, 'None', or a valid IP address", + "field": "spec.clusterIP" + } + ] + }, + "code": 422 +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/3.edited b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/3.edited new file mode 100755 index 00000000000..46dd87bdec1 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/3.edited @@ -0,0 +1,33 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +# services "svc1" was not valid: +# * spec.clusterIP: Invalid value: "10.0.0.146.1": field is immutable +# * spec.clusterIP: Invalid value: "10.0.0.146.1": must be empty, 'None', or a valid IP address +# +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: 2017-02-01T21:14:09Z + labels: + app: svc1 + new-label: new-value + name: svc1 + namespace: edit-test + resourceVersion: "20820" + selfLink: /api/v1/namespaces/edit-test/services/svc1 + uid: 5f7da8db-e8c3-11e6-b7e2-acbc32c1ca87 +spec: + clusterIP: 10.0.0.146 + ports: + - name: "80" + port: 82 + protocol: TCP + targetPort: 80 + selector: + app: svc1 + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/3.original b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/3.original new file mode 100755 index 00000000000..f06ff2cf6c7 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/3.original @@ -0,0 +1,33 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +# services "svc1" was not valid: +# * spec.clusterIP: Invalid value: "10.0.0.146.1": field is immutable +# * spec.clusterIP: Invalid value: "10.0.0.146.1": must be empty, 'None', or a valid IP address +# +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: 2017-02-01T21:14:09Z + labels: + app: svc1 + new-label: new-value + name: svc1 + namespace: edit-test + resourceVersion: "20820" + selfLink: /api/v1/namespaces/edit-test/services/svc1 + uid: 5f7da8db-e8c3-11e6-b7e2-acbc32c1ca87 +spec: + clusterIP: 10.0.0.146.1 + ports: + - name: "80" + port: 81 + protocol: TCP + targetPort: 80 + selector: + app: svc1 + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/4.request b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/4.request new file mode 100755 index 00000000000..f6ff34a556d --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/4.request @@ -0,0 +1,16 @@ +{ + "spec": { + "ports": [ + { + "$patch": "delete", + "port": 81 + }, + { + "name": "80", + "port": 82, + "protocol": "TCP", + "targetPort": 80 + } + ] + } +} \ No newline at end of file diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/4.response b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/4.response new file mode 100755 index 00000000000..a306fb41016 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/4.response @@ -0,0 +1,35 @@ +{ + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "svc1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/services/svc1", + "uid": "5f7da8db-e8c3-11e6-b7e2-acbc32c1ca87", + "resourceVersion": "21361", + "creationTimestamp": "2017-02-01T21:14:09Z", + "labels": { + "app": "svc1", + "new-label": "new-value" + } + }, + "spec": { + "ports": [ + { + "name": "80", + "protocol": "TCP", + "port": 82, + "targetPort": 80 + } + ], + "selector": { + "app": "svc1" + }, + "clusterIP": "10.0.0.146", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/test.yaml b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/test.yaml new file mode 100755 index 00000000000..8ead2670755 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-edit-error-reedit/test.yaml @@ -0,0 +1,38 @@ +description: add a testcase description +mode: edit +args: +- service +- svc1 +namespace: edit-test +expectedStdout: +- service "svc1" edited +expectedStderr: +- "error: services \"svc1\" is invalid" +expectedExitCode: 0 +steps: +- type: request + expectedMethod: GET + expectedPath: /api/v1/namespaces/edit-test/services/svc1 + expectedInput: 0.request + resultingStatusCode: 200 + resultingOutput: 0.response +- type: edit + expectedInput: 1.original + resultingOutput: 1.edited +- type: request + expectedMethod: PATCH + expectedPath: /api/v1/namespaces/edit-test/services/svc1 + expectedContentType: application/strategic-merge-patch+json + expectedInput: 2.request + resultingStatusCode: 422 + resultingOutput: 2.response +- type: edit + expectedInput: 3.original + resultingOutput: 3.edited +- type: request + expectedMethod: PATCH + expectedPath: /api/v1/namespaces/edit-test/services/svc1 + expectedContentType: application/strategic-merge-patch+json + expectedInput: 4.request + resultingStatusCode: 200 + resultingOutput: 4.response diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-immutable-name/0.request b/pkg/kubectl/cmd/testdata/edit/testcase-immutable-name/0.request new file mode 100755 index 00000000000..e69de29bb2d diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-immutable-name/0.response b/pkg/kubectl/cmd/testdata/edit/testcase-immutable-name/0.response new file mode 100755 index 00000000000..f452881e073 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-immutable-name/0.response @@ -0,0 +1,24 @@ +{ + "kind": "ConfigMapList", + "apiVersion": "v1", + "metadata": { + "selfLink": "/api/v1/namespaces/edit-test/configmaps", + "resourceVersion": "2308" + }, + "items": [ + { + "metadata": { + "name": "cm1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/configmaps/cm1", + "uid": "b09bffab-e9d7-11e6-8c3b-acbc32c1ca87", + "resourceVersion": "2071", + "creationTimestamp": "2017-02-03T06:12:07Z" + }, + "data": { + "baz": "qux", + "foo": "changed-value2" + } + } + ] +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-immutable-name/1.edited b/pkg/kubectl/cmd/testdata/edit/testcase-immutable-name/1.edited new file mode 100755 index 00000000000..601b5d97da8 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-immutable-name/1.edited @@ -0,0 +1,16 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +data: + baz: qux + foo: changed-value2 +kind: ConfigMap +metadata: + creationTimestamp: 2017-02-03T06:12:07Z + name: cm1-modified + namespace: edit-test + resourceVersion: "2071" + selfLink: /api/v1/namespaces/edit-test/configmaps/cm1 + uid: b09bffab-e9d7-11e6-8c3b-acbc32c1ca87 diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-immutable-name/1.original b/pkg/kubectl/cmd/testdata/edit/testcase-immutable-name/1.original new file mode 100755 index 00000000000..2a801cfdea7 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-immutable-name/1.original @@ -0,0 +1,16 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +data: + baz: qux + foo: changed-value2 +kind: ConfigMap +metadata: + creationTimestamp: 2017-02-03T06:12:07Z + name: cm1 + namespace: edit-test + resourceVersion: "2071" + selfLink: /api/v1/namespaces/edit-test/configmaps/cm1 + uid: b09bffab-e9d7-11e6-8c3b-acbc32c1ca87 diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-immutable-name/test.yaml b/pkg/kubectl/cmd/testdata/edit/testcase-immutable-name/test.yaml new file mode 100755 index 00000000000..efcb3916847 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-immutable-name/test.yaml @@ -0,0 +1,18 @@ +description: try to mutate a fixed field +mode: edit +args: +- configmap +namespace: "edit-test" +expectedStderr: +- At least one of apiVersion, kind and name was changed +expectedExitCode: 1 +steps: +- type: request + expectedMethod: GET + expectedPath: /api/v1/namespaces/edit-test/configmaps + expectedInput: 0.request + resultingStatusCode: 200 + resultingOutput: 0.response +- type: edit + expectedInput: 1.original + resultingOutput: 1.edited diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/0.request b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/0.request new file mode 100755 index 00000000000..e69de29bb2d diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/0.response b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/0.response new file mode 100755 index 00000000000..de6ce9b1d8f --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/0.response @@ -0,0 +1,24 @@ +{ + "kind": "ConfigMapList", + "apiVersion": "v1", + "metadata": { + "selfLink": "/api/v1/namespaces/edit-test/configmaps", + "resourceVersion": "1934" + }, + "items": [ + { + "metadata": { + "name": "cm1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/configmaps/cm1", + "uid": "b09bffab-e9d7-11e6-8c3b-acbc32c1ca87", + "resourceVersion": "1903", + "creationTimestamp": "2017-02-03T06:12:07Z" + }, + "data": { + "baz": "qux", + "foo": "changed-value" + } + } + ] +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/1.request b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/1.request new file mode 100755 index 00000000000..e69de29bb2d diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/1.response b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/1.response new file mode 100755 index 00000000000..ef805f7dde6 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/1.response @@ -0,0 +1,39 @@ +{ + "kind": "ServiceList", + "apiVersion": "v1", + "metadata": { + "selfLink": "/api/v1/namespaces/edit-test/services", + "resourceVersion": "1934" + }, + "items": [ + { + "metadata": { + "name": "svc1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/services/svc1", + "uid": "9bec82be-e9d7-11e6-8c3b-acbc32c1ca87", + "resourceVersion": "1904", + "creationTimestamp": "2017-02-03T06:11:32Z", + "labels": { + "app": "svc1" + } + }, + "spec": { + "ports": [ + { + "name": "80", + "protocol": "TCP", + "port": 82, + "targetPort": 81 + } + ], + "clusterIP": "10.0.0.248", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } + } + ] +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/10.request b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/10.request new file mode 100755 index 00000000000..5b1e95c8326 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/10.request @@ -0,0 +1,5 @@ +{ + "data": { + "foo": "changed-value2" + } +} \ No newline at end of file diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/10.response b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/10.response new file mode 100755 index 00000000000..82f246ab797 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/10.response @@ -0,0 +1,16 @@ +{ + "kind": "ConfigMap", + "apiVersion": "v1", + "metadata": { + "name": "cm1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/configmaps/cm1", + "uid": "b09bffab-e9d7-11e6-8c3b-acbc32c1ca87", + "resourceVersion": "2071", + "creationTimestamp": "2017-02-03T06:12:07Z" + }, + "data": { + "baz": "qux", + "foo": "changed-value2" + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/2.edited b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/2.edited new file mode 100755 index 00000000000..739e5f0b920 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/2.edited @@ -0,0 +1,42 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +items: +- apiVersion: v1 + kind: Service + metadata: + creationTimestamp: 2017-02-03T06:11:32Z + labels: + app: svc1 + name: svc1 + namespace: edit-test + resourceVersion: "1904" + selfLink: /api/v1/namespaces/edit-test/services/svc1 + uid: 9bec82be-e9d7-11e6-8c3b-acbc32c1ca87 + spec: + clusterIP: 10.0.0.10 + ports: + - name: "80" + port: 82 + protocol: VHF + targetPort: 81 + sessionAffinity: None + type: ClusterIP + status: + loadBalancer: {} +- apiVersion: v1 + data: + baz: qux + foo: changed-value2 + kind: ConfigMap + metadata: + creationTimestamp: 2017-02-03T06:12:07Z + name: cm1 + namespace: edit-test + resourceVersion: "1903" + selfLink: /api/v1/namespaces/edit-test/configmaps/cm1 + uid: b09bffab-e9d7-11e6-8c3b-acbc32c1ca87 +kind: List +metadata: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/2.original b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/2.original new file mode 100755 index 00000000000..b8ddf66d869 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/2.original @@ -0,0 +1,42 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +items: +- apiVersion: v1 + data: + baz: qux + foo: changed-value + kind: ConfigMap + metadata: + creationTimestamp: 2017-02-03T06:12:07Z + name: cm1 + namespace: edit-test + resourceVersion: "1903" + selfLink: /api/v1/namespaces/edit-test/configmaps/cm1 + uid: b09bffab-e9d7-11e6-8c3b-acbc32c1ca87 +- apiVersion: v1 + kind: Service + metadata: + creationTimestamp: 2017-02-03T06:11:32Z + labels: + app: svc1 + name: svc1 + namespace: edit-test + resourceVersion: "1904" + selfLink: /api/v1/namespaces/edit-test/services/svc1 + uid: 9bec82be-e9d7-11e6-8c3b-acbc32c1ca87 + spec: + clusterIP: 10.0.0.248 + ports: + - name: "80" + port: 82 + protocol: TCP + targetPort: 81 + sessionAffinity: None + type: ClusterIP + status: + loadBalancer: {} +kind: List +metadata: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/3.request b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/3.request new file mode 100755 index 00000000000..a5d17bf7e0b --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/3.request @@ -0,0 +1,11 @@ +{ + "spec": { + "clusterIP": "10.0.0.10", + "ports": [ + { + "port": 82, + "protocol": "VHF" + } + ] + } +} \ No newline at end of file diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/3.response b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/3.response new file mode 100755 index 00000000000..b40462575f6 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/3.response @@ -0,0 +1,25 @@ +{ + "kind": "Status", + "apiVersion": "v1", + "metadata": {}, + "status": "Failure", + "message": "Service \"svc1\" is invalid: [spec.clusterIP: Invalid value: \"10.0.0.10\": field is immutable, spec.ports[0].protocol: Unsupported value: \"VHF\": supported values: TCP, UDP]", + "reason": "Invalid", + "details": { + "name": "svc1", + "kind": "Service", + "causes": [ + { + "reason": "FieldValueInvalid", + "message": "Invalid value: \"10.0.0.10\": field is immutable", + "field": "spec.clusterIP" + }, + { + "reason": "FieldValueNotSupported", + "message": "Unsupported value: \"VHF\": supported values: TCP, UDP", + "field": "spec.ports[0].protocol" + } + ] + }, + "code": 422 +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/4.request b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/4.request new file mode 100755 index 00000000000..5b1e95c8326 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/4.request @@ -0,0 +1,5 @@ +{ + "data": { + "foo": "changed-value2" + } +} \ No newline at end of file diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/4.response b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/4.response new file mode 100755 index 00000000000..1bf423cb5e8 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/4.response @@ -0,0 +1,16 @@ +{ + "kind": "ConfigMap", + "apiVersion": "v1", + "metadata": { + "name": "cm1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/configmaps/cm1", + "uid": "b09bffab-e9d7-11e6-8c3b-acbc32c1ca87", + "resourceVersion": "2017", + "creationTimestamp": "2017-02-03T06:12:07Z" + }, + "data": { + "baz": "qux", + "foo": "changed-value2" + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/5.edited b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/5.edited new file mode 100755 index 00000000000..3aa682b445d --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/5.edited @@ -0,0 +1,47 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +# services "svc1" was not valid: +# * spec.clusterIP: Invalid value: "10.0.0.10": field is immutable +# * spec.ports[0].protocol: Unsupported value: "VHF": supported values: TCP, UDP +# +apiVersion: v1 +items: +- apiVersion: v1 + kind: Service + metadata: + creationTimestamp: 2017-02-03T06:11:32Z + labels: + app: svc1 + newvalue: modified + name: svc1 + namespace: edit-test + resourceVersion: "1904" + selfLink: /api/v1/namespaces/edit-test/services/svc1 + uid: 9bec82be-e9d7-11e6-8c3b-acbc32c1ca87 + spec: + clusterIP: 10.0.0.248 + ports: + - name: "80" + port: 83 + protocol: VHF + targetPort: 81 + sessionAffinity: None + type: ClusterIP + status: + loadBalancer: {} +- apiVersion: v1 + data: + baz: qux + foo: changed-value2 + kind: ConfigMap + metadata: + creationTimestamp: 2017-02-03T06:12:07Z + name: cm1 + namespace: edit-test + resourceVersion: "1903" + selfLink: /api/v1/namespaces/edit-test/configmaps/cm1 + uid: b09bffab-e9d7-11e6-8c3b-acbc32c1ca87 +kind: List +metadata: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/5.original b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/5.original new file mode 100755 index 00000000000..7913d211ac7 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/5.original @@ -0,0 +1,46 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +# services "svc1" was not valid: +# * spec.clusterIP: Invalid value: "10.0.0.10": field is immutable +# * spec.ports[0].protocol: Unsupported value: "VHF": supported values: TCP, UDP +# +apiVersion: v1 +items: +- apiVersion: v1 + kind: Service + metadata: + creationTimestamp: 2017-02-03T06:11:32Z + labels: + app: svc1 + name: svc1 + namespace: edit-test + resourceVersion: "1904" + selfLink: /api/v1/namespaces/edit-test/services/svc1 + uid: 9bec82be-e9d7-11e6-8c3b-acbc32c1ca87 + spec: + clusterIP: 10.0.0.10 + ports: + - name: "80" + port: 82 + protocol: VHF + targetPort: 81 + sessionAffinity: None + type: ClusterIP + status: + loadBalancer: {} +- apiVersion: v1 + data: + baz: qux + foo: changed-value2 + kind: ConfigMap + metadata: + creationTimestamp: 2017-02-03T06:12:07Z + name: cm1 + namespace: edit-test + resourceVersion: "1903" + selfLink: /api/v1/namespaces/edit-test/configmaps/cm1 + uid: b09bffab-e9d7-11e6-8c3b-acbc32c1ca87 +kind: List +metadata: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/6.request b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/6.request new file mode 100755 index 00000000000..3dd3605fad0 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/6.request @@ -0,0 +1,21 @@ +{ + "metadata": { + "labels": { + "newvalue": "modified" + } + }, + "spec": { + "ports": [ + { + "$patch": "delete", + "port": 82 + }, + { + "name": "80", + "port": 83, + "protocol": "VHF", + "targetPort": 81 + } + ] + } +} \ No newline at end of file diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/6.response b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/6.response new file mode 100755 index 00000000000..726f0fd487b --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/6.response @@ -0,0 +1,20 @@ +{ + "kind": "Status", + "apiVersion": "v1", + "metadata": {}, + "status": "Failure", + "message": "Service \"svc1\" is invalid: spec.ports[0].protocol: Unsupported value: \"VHF\": supported values: TCP, UDP", + "reason": "Invalid", + "details": { + "name": "svc1", + "kind": "Service", + "causes": [ + { + "reason": "FieldValueNotSupported", + "message": "Unsupported value: \"VHF\": supported values: TCP, UDP", + "field": "spec.ports[0].protocol" + } + ] + }, + "code": 422 +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/7.request b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/7.request new file mode 100755 index 00000000000..5b1e95c8326 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/7.request @@ -0,0 +1,5 @@ +{ + "data": { + "foo": "changed-value2" + } +} \ No newline at end of file diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/7.response b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/7.response new file mode 100755 index 00000000000..1bf423cb5e8 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/7.response @@ -0,0 +1,16 @@ +{ + "kind": "ConfigMap", + "apiVersion": "v1", + "metadata": { + "name": "cm1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/configmaps/cm1", + "uid": "b09bffab-e9d7-11e6-8c3b-acbc32c1ca87", + "resourceVersion": "2017", + "creationTimestamp": "2017-02-03T06:12:07Z" + }, + "data": { + "baz": "qux", + "foo": "changed-value2" + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/8.edited b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/8.edited new file mode 100755 index 00000000000..7ad39a82a45 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/8.edited @@ -0,0 +1,46 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +# services "svc1" was not valid: +# * spec.ports[0].protocol: Unsupported value: "VHF": supported values: TCP, UDP +# +apiVersion: v1 +items: +- apiVersion: v1 + kind: Service + metadata: + creationTimestamp: 2017-02-03T06:11:32Z + labels: + app: svc1 + newvalue: modified + name: svc1 + namespace: edit-test + resourceVersion: "1904" + selfLink: /api/v1/namespaces/edit-test/services/svc1 + uid: 9bec82be-e9d7-11e6-8c3b-acbc32c1ca87 + spec: + clusterIP: 10.0.0.248 + ports: + - name: "80" + port: 83 + protocol: TCP + targetPort: 81 + sessionAffinity: None + type: ClusterIP + status: + loadBalancer: {} +- apiVersion: v1 + data: + baz: qux + foo: changed-value2 + kind: ConfigMap + metadata: + creationTimestamp: 2017-02-03T06:12:07Z + name: cm1 + namespace: edit-test + resourceVersion: "1903" + selfLink: /api/v1/namespaces/edit-test/configmaps/cm1 + uid: b09bffab-e9d7-11e6-8c3b-acbc32c1ca87 +kind: List +metadata: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/8.original b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/8.original new file mode 100755 index 00000000000..4d82b22b206 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/8.original @@ -0,0 +1,46 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +# services "svc1" was not valid: +# * spec.ports[0].protocol: Unsupported value: "VHF": supported values: TCP, UDP +# +apiVersion: v1 +items: +- apiVersion: v1 + kind: Service + metadata: + creationTimestamp: 2017-02-03T06:11:32Z + labels: + app: svc1 + newvalue: modified + name: svc1 + namespace: edit-test + resourceVersion: "1904" + selfLink: /api/v1/namespaces/edit-test/services/svc1 + uid: 9bec82be-e9d7-11e6-8c3b-acbc32c1ca87 + spec: + clusterIP: 10.0.0.248 + ports: + - name: "80" + port: 83 + protocol: VHF + targetPort: 81 + sessionAffinity: None + type: ClusterIP + status: + loadBalancer: {} +- apiVersion: v1 + data: + baz: qux + foo: changed-value2 + kind: ConfigMap + metadata: + creationTimestamp: 2017-02-03T06:12:07Z + name: cm1 + namespace: edit-test + resourceVersion: "1903" + selfLink: /api/v1/namespaces/edit-test/configmaps/cm1 + uid: b09bffab-e9d7-11e6-8c3b-acbc32c1ca87 +kind: List +metadata: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/9.request b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/9.request new file mode 100755 index 00000000000..2fe0faa445d --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/9.request @@ -0,0 +1,21 @@ +{ + "metadata": { + "labels": { + "newvalue": "modified" + } + }, + "spec": { + "ports": [ + { + "$patch": "delete", + "port": 82 + }, + { + "name": "80", + "port": 83, + "protocol": "TCP", + "targetPort": 81 + } + ] + } +} \ No newline at end of file diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/9.response b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/9.response new file mode 100755 index 00000000000..d88f9940946 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/9.response @@ -0,0 +1,32 @@ +{ + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "svc1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/services/svc1", + "uid": "9bec82be-e9d7-11e6-8c3b-acbc32c1ca87", + "resourceVersion": "2070", + "creationTimestamp": "2017-02-03T06:11:32Z", + "labels": { + "app": "svc1", + "newvalue": "modified" + } + }, + "spec": { + "ports": [ + { + "name": "80", + "protocol": "TCP", + "port": 83, + "targetPort": 81 + } + ], + "clusterIP": "10.0.0.248", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/test.yaml b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/test.yaml new file mode 100755 index 00000000000..03f6ca90419 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-errors/test.yaml @@ -0,0 +1,73 @@ +description: edit lists with errors and resubmit +mode: edit +args: +- configmaps,services +namespace: "edit-test" +expectedStdout: +- configmap "cm1" edited +- service "svc1" edited +expectedExitCode: 0 +steps: +- type: request + expectedMethod: GET + expectedPath: /api/v1/namespaces/edit-test/configmaps + expectedInput: 0.request + resultingStatusCode: 200 + resultingOutput: 0.response +- type: request + expectedMethod: GET + expectedPath: /api/v1/namespaces/edit-test/services + expectedInput: 1.request + resultingStatusCode: 200 + resultingOutput: 1.response +- type: edit + expectedInput: 2.original + resultingOutput: 2.edited +- type: request + expectedMethod: PATCH + expectedPath: /api/v1/namespaces/edit-test/services/svc1 + expectedContentType: application/strategic-merge-patch+json + expectedInput: 3.request + resultingStatusCode: 422 + resultingOutput: 3.response +- type: request + expectedMethod: PATCH + expectedPath: /api/v1/namespaces/edit-test/configmaps/cm1 + expectedContentType: application/strategic-merge-patch+json + expectedInput: 4.request + resultingStatusCode: 200 + resultingOutput: 4.response +- type: edit + expectedInput: 5.original + resultingOutput: 5.edited +- type: request + expectedMethod: PATCH + expectedPath: /api/v1/namespaces/edit-test/services/svc1 + expectedContentType: application/strategic-merge-patch+json + expectedInput: 6.request + resultingStatusCode: 422 + resultingOutput: 6.response +- type: request + expectedMethod: PATCH + expectedPath: /api/v1/namespaces/edit-test/configmaps/cm1 + expectedContentType: application/strategic-merge-patch+json + expectedInput: 7.request + resultingStatusCode: 200 + resultingOutput: 7.response +- type: edit + expectedInput: 8.original + resultingOutput: 8.edited +- type: request + expectedMethod: PATCH + expectedPath: /api/v1/namespaces/edit-test/services/svc1 + expectedContentType: application/strategic-merge-patch+json + expectedInput: 9.request + resultingStatusCode: 200 + resultingOutput: 9.response +- type: request + expectedMethod: PATCH + expectedPath: /api/v1/namespaces/edit-test/configmaps/cm1 + expectedContentType: application/strategic-merge-patch+json + expectedInput: 10.request + resultingStatusCode: 200 + resultingOutput: 10.response diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list/0.request b/pkg/kubectl/cmd/testdata/edit/testcase-list/0.request new file mode 100755 index 00000000000..e69de29bb2d diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list/0.response b/pkg/kubectl/cmd/testdata/edit/testcase-list/0.response new file mode 100755 index 00000000000..98538a48e39 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list/0.response @@ -0,0 +1,18 @@ +{ + "kind": "ConfigMap", + "apiVersion": "v1", + "metadata": { + "name": "cm1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/configmaps/cm1", + "uid": "b09bffab-e9d7-11e6-8c3b-acbc32c1ca87", + "resourceVersion": "1414", + "creationTimestamp": "2017-02-03T06:12:07Z" + }, + "data": { + "baz": "qux", + "foo": "changed-value", + "new-data": "new-value", + "new-data2": "new-value" + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list/1.request b/pkg/kubectl/cmd/testdata/edit/testcase-list/1.request new file mode 100755 index 00000000000..e69de29bb2d diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list/1.response b/pkg/kubectl/cmd/testdata/edit/testcase-list/1.response new file mode 100755 index 00000000000..4b734d58403 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list/1.response @@ -0,0 +1,32 @@ +{ + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "svc1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/services/svc1", + "uid": "9bec82be-e9d7-11e6-8c3b-acbc32c1ca87", + "resourceVersion": "1064", + "creationTimestamp": "2017-02-03T06:11:32Z", + "labels": { + "app": "svc1", + "new-label": "foo" + } + }, + "spec": { + "ports": [ + { + "name": "80", + "protocol": "TCP", + "port": 81, + "targetPort": 81 + } + ], + "clusterIP": "10.0.0.248", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list/2.edited b/pkg/kubectl/cmd/testdata/edit/testcase-list/2.edited new file mode 100755 index 00000000000..641889169f8 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list/2.edited @@ -0,0 +1,47 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +items: +- apiVersion: v1 + data: + baz: qux + foo: changed-value + new-data: new-value + new-data2: new-value + new-data3: newivalue + kind: ConfigMap + metadata: + creationTimestamp: 2017-02-03T06:12:07Z + name: cm1 + namespace: edit-test + resourceVersion: "1414" + selfLink: /api/v1/namespaces/edit-test/configmaps/cm1 + uid: b09bffab-e9d7-11e6-8c3b-acbc32c1ca87 +- apiVersion: v1 + kind: Service + metadata: + creationTimestamp: 2017-02-03T06:11:32Z + labels: + app: svc1 + new-label: foo + new-label2: foo2 + name: svc1 + namespace: edit-test + resourceVersion: "1064" + selfLink: /api/v1/namespaces/edit-test/services/svc1 + uid: 9bec82be-e9d7-11e6-8c3b-acbc32c1ca87 + spec: + clusterIP: 10.0.0.248 + ports: + - name: "80" + port: 82 + protocol: TCP + targetPort: 81 + sessionAffinity: None + type: ClusterIP + status: + loadBalancer: {} +kind: List +metadata: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list/2.original b/pkg/kubectl/cmd/testdata/edit/testcase-list/2.original new file mode 100755 index 00000000000..c69a566ca6f --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list/2.original @@ -0,0 +1,45 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +items: +- apiVersion: v1 + data: + baz: qux + foo: changed-value + new-data: new-value + new-data2: new-value + kind: ConfigMap + metadata: + creationTimestamp: 2017-02-03T06:12:07Z + name: cm1 + namespace: edit-test + resourceVersion: "1414" + selfLink: /api/v1/namespaces/edit-test/configmaps/cm1 + uid: b09bffab-e9d7-11e6-8c3b-acbc32c1ca87 +- apiVersion: v1 + kind: Service + metadata: + creationTimestamp: 2017-02-03T06:11:32Z + labels: + app: svc1 + new-label: foo + name: svc1 + namespace: edit-test + resourceVersion: "1064" + selfLink: /api/v1/namespaces/edit-test/services/svc1 + uid: 9bec82be-e9d7-11e6-8c3b-acbc32c1ca87 + spec: + clusterIP: 10.0.0.248 + ports: + - name: "80" + port: 81 + protocol: TCP + targetPort: 81 + sessionAffinity: None + type: ClusterIP + status: + loadBalancer: {} +kind: List +metadata: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list/3.request b/pkg/kubectl/cmd/testdata/edit/testcase-list/3.request new file mode 100755 index 00000000000..ba542f24b9d --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list/3.request @@ -0,0 +1,5 @@ +{ + "data": { + "new-data3": "newivalue" + } +} \ No newline at end of file diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list/3.response b/pkg/kubectl/cmd/testdata/edit/testcase-list/3.response new file mode 100755 index 00000000000..57aa154c9c3 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list/3.response @@ -0,0 +1,19 @@ +{ + "kind": "ConfigMap", + "apiVersion": "v1", + "metadata": { + "name": "cm1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/configmaps/cm1", + "uid": "b09bffab-e9d7-11e6-8c3b-acbc32c1ca87", + "resourceVersion": "1465", + "creationTimestamp": "2017-02-03T06:12:07Z" + }, + "data": { + "baz": "qux", + "foo": "changed-value", + "new-data": "new-value", + "new-data2": "new-value", + "new-data3": "newivalue" + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list/4.request b/pkg/kubectl/cmd/testdata/edit/testcase-list/4.request new file mode 100755 index 00000000000..f1274be09ab --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list/4.request @@ -0,0 +1,21 @@ +{ + "metadata": { + "labels": { + "new-label2": "foo2" + } + }, + "spec": { + "ports": [ + { + "$patch": "delete", + "port": 81 + }, + { + "name": "80", + "port": 82, + "protocol": "TCP", + "targetPort": 81 + } + ] + } +} \ No newline at end of file diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list/4.response b/pkg/kubectl/cmd/testdata/edit/testcase-list/4.response new file mode 100755 index 00000000000..e242a83c635 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list/4.response @@ -0,0 +1,33 @@ +{ + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "svc1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/services/svc1", + "uid": "9bec82be-e9d7-11e6-8c3b-acbc32c1ca87", + "resourceVersion": "1466", + "creationTimestamp": "2017-02-03T06:11:32Z", + "labels": { + "app": "svc1", + "new-label": "foo", + "new-label2": "foo2" + } + }, + "spec": { + "ports": [ + { + "name": "80", + "protocol": "TCP", + "port": 82, + "targetPort": 81 + } + ], + "clusterIP": "10.0.0.248", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list/test.yaml b/pkg/kubectl/cmd/testdata/edit/testcase-list/test.yaml new file mode 100755 index 00000000000..1ee9e35fafb --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list/test.yaml @@ -0,0 +1,40 @@ +description: add a testcase description +mode: edit +args: +- configmaps/cm1 +- service/svc1 +namespace: "edit-test" +expectedStdout: +- configmap "cm1" edited +- service "svc1" edited +expectedExitCode: 0 +steps: +- type: request + expectedMethod: GET + expectedPath: /api/v1/namespaces/edit-test/configmaps/cm1 + expectedInput: 0.request + resultingStatusCode: 200 + resultingOutput: 0.response +- type: request + expectedMethod: GET + expectedPath: /api/v1/namespaces/edit-test/services/svc1 + expectedInput: 1.request + resultingStatusCode: 200 + resultingOutput: 1.response +- type: edit + expectedInput: 2.original + resultingOutput: 2.edited +- type: request + expectedMethod: PATCH + expectedPath: /api/v1/namespaces/edit-test/configmaps/cm1 + expectedContentType: application/strategic-merge-patch+json + expectedInput: 3.request + resultingStatusCode: 200 + resultingOutput: 3.response +- type: request + expectedMethod: PATCH + expectedPath: /api/v1/namespaces/edit-test/services/svc1 + expectedContentType: application/strategic-merge-patch+json + expectedInput: 4.request + resultingStatusCode: 200 + resultingOutput: 4.response diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-missing-service/0.request b/pkg/kubectl/cmd/testdata/edit/testcase-missing-service/0.request new file mode 100755 index 00000000000..e69de29bb2d diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-missing-service/0.response b/pkg/kubectl/cmd/testdata/edit/testcase-missing-service/0.response new file mode 100755 index 00000000000..d55d1033956 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-missing-service/0.response @@ -0,0 +1,13 @@ +{ + "kind": "Status", + "apiVersion": "v1", + "metadata": {}, + "status": "Failure", + "message": "services \"missing\" not found", + "reason": "NotFound", + "details": { + "name": "missing", + "kind": "services" + }, + "code": 404 +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-missing-service/test.yaml b/pkg/kubectl/cmd/testdata/edit/testcase-missing-service/test.yaml new file mode 100755 index 00000000000..87b05841ab0 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-missing-service/test.yaml @@ -0,0 +1,15 @@ +description: add a testcase description +mode: edit +args: +- service/missing +namespace: "default" +expectedStderr: +- services "missing" not found +expectedExitCode: 1 +steps: +- type: request + expectedMethod: GET + expectedPath: /api/v1/namespaces/default/services/missing + expectedInput: 0.request + resultingStatusCode: 404 + resultingOutput: 0.response diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-no-op/0.request b/pkg/kubectl/cmd/testdata/edit/testcase-no-op/0.request new file mode 100755 index 00000000000..e69de29bb2d diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-no-op/0.response b/pkg/kubectl/cmd/testdata/edit/testcase-no-op/0.response new file mode 100755 index 00000000000..0945091d1d4 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-no-op/0.response @@ -0,0 +1,12 @@ +{ + "kind": "ConfigMap", + "apiVersion": "v1", + "metadata": { + "name": "mymap", + "namespace": "default", + "selfLink": "/api/v1/namespaces/default/configmaps/mymap", + "uid": "dbde42e9-e9d5-11e6-8c3b-acbc32c1ca87", + "resourceVersion": "149", + "creationTimestamp": "2017-02-03T05:59:00Z" + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-no-op/1.edited b/pkg/kubectl/cmd/testdata/edit/testcase-no-op/1.edited new file mode 100755 index 00000000000..91de933c413 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-no-op/1.edited @@ -0,0 +1,13 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +kind: ConfigMap +metadata: + creationTimestamp: 2017-02-03T05:59:00Z + name: mymap + namespace: default + resourceVersion: "149" + selfLink: /api/v1/namespaces/default/configmaps/mymap + uid: dbde42e9-e9d5-11e6-8c3b-acbc32c1ca87 diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-no-op/1.original b/pkg/kubectl/cmd/testdata/edit/testcase-no-op/1.original new file mode 100755 index 00000000000..91de933c413 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-no-op/1.original @@ -0,0 +1,13 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +kind: ConfigMap +metadata: + creationTimestamp: 2017-02-03T05:59:00Z + name: mymap + namespace: default + resourceVersion: "149" + selfLink: /api/v1/namespaces/default/configmaps/mymap + uid: dbde42e9-e9d5-11e6-8c3b-acbc32c1ca87 diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-no-op/test.yaml b/pkg/kubectl/cmd/testdata/edit/testcase-no-op/test.yaml new file mode 100755 index 00000000000..6b7b108fd35 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-no-op/test.yaml @@ -0,0 +1,18 @@ +description: no-op edit +mode: edit +args: +- configmap/mymap +namespace: "default" +expectedStderr: +- Edit cancelled, no changes made. +expectedExitCode: 0 +steps: +- type: request + expectedMethod: GET + expectedPath: /api/v1/namespaces/default/configmaps/mymap + expectedInput: 0.request + resultingStatusCode: 200 + resultingOutput: 0.response +- type: edit + expectedInput: 1.original + resultingOutput: 1.edited diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-single-service/0.request b/pkg/kubectl/cmd/testdata/edit/testcase-single-service/0.request new file mode 100755 index 00000000000..e69de29bb2d diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-single-service/0.response b/pkg/kubectl/cmd/testdata/edit/testcase-single-service/0.response new file mode 100755 index 00000000000..2d45240d6c1 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-single-service/0.response @@ -0,0 +1,34 @@ +{ + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "svc1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/services/svc1", + "uid": "5f7da8db-e8c3-11e6-b7e2-acbc32c1ca87", + "resourceVersion": "20715", + "creationTimestamp": "2017-02-01T21:14:09Z", + "labels": { + "app": "svc1" + } + }, + "spec": { + "ports": [ + { + "name": "80", + "protocol": "TCP", + "port": 80, + "targetPort": 80 + } + ], + "selector": { + "app": "svc1" + }, + "clusterIP": "10.0.0.146", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-single-service/1.edited b/pkg/kubectl/cmd/testdata/edit/testcase-single-service/1.edited new file mode 100755 index 00000000000..0400429b95d --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-single-service/1.edited @@ -0,0 +1,29 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: 2017-02-01T21:14:09Z + labels: + app: svc1 + new-label: new-value + name: svc1 + namespace: edit-test + resourceVersion: "20715" + selfLink: /api/v1/namespaces/edit-test/services/svc1 + uid: 5f7da8db-e8c3-11e6-b7e2-acbc32c1ca87 +spec: + clusterIP: 10.0.0.146 + ports: + - name: "80" + port: 81 + protocol: TCP + targetPort: 80 + selector: + app: svc1 + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-single-service/1.original b/pkg/kubectl/cmd/testdata/edit/testcase-single-service/1.original new file mode 100755 index 00000000000..166898cea19 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-single-service/1.original @@ -0,0 +1,28 @@ +# Please edit the object below. Lines beginning with a '#' will be ignored, +# and an empty file will abort the edit. If an error occurs while saving this file will be +# reopened with the relevant failures. +# +apiVersion: v1 +kind: Service +metadata: + creationTimestamp: 2017-02-01T21:14:09Z + labels: + app: svc1 + name: svc1 + namespace: edit-test + resourceVersion: "20715" + selfLink: /api/v1/namespaces/edit-test/services/svc1 + uid: 5f7da8db-e8c3-11e6-b7e2-acbc32c1ca87 +spec: + clusterIP: 10.0.0.146 + ports: + - name: "80" + port: 80 + protocol: TCP + targetPort: 80 + selector: + app: svc1 + sessionAffinity: None + type: ClusterIP +status: + loadBalancer: {} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-single-service/2.request b/pkg/kubectl/cmd/testdata/edit/testcase-single-service/2.request new file mode 100755 index 00000000000..4a32ac7519d --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-single-service/2.request @@ -0,0 +1,21 @@ +{ + "metadata": { + "labels": { + "new-label": "new-value" + } + }, + "spec": { + "ports": [ + { + "$patch": "delete", + "port": 80 + }, + { + "name": "80", + "port": 81, + "protocol": "TCP", + "targetPort": 80 + } + ] + } +} \ No newline at end of file diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-single-service/2.response b/pkg/kubectl/cmd/testdata/edit/testcase-single-service/2.response new file mode 100755 index 00000000000..4fb08268eb3 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-single-service/2.response @@ -0,0 +1,35 @@ +{ + "kind": "Service", + "apiVersion": "v1", + "metadata": { + "name": "svc1", + "namespace": "edit-test", + "selfLink": "/api/v1/namespaces/edit-test/services/svc1", + "uid": "5f7da8db-e8c3-11e6-b7e2-acbc32c1ca87", + "resourceVersion": "20820", + "creationTimestamp": "2017-02-01T21:14:09Z", + "labels": { + "app": "svc1", + "new-label": "new-value" + } + }, + "spec": { + "ports": [ + { + "name": "80", + "protocol": "TCP", + "port": 81, + "targetPort": 80 + } + ], + "selector": { + "app": "svc1" + }, + "clusterIP": "10.0.0.146", + "type": "ClusterIP", + "sessionAffinity": "None" + }, + "status": { + "loadBalancer": {} + } +} diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-single-service/test.yaml b/pkg/kubectl/cmd/testdata/edit/testcase-single-service/test.yaml new file mode 100755 index 00000000000..5b48baa9650 --- /dev/null +++ b/pkg/kubectl/cmd/testdata/edit/testcase-single-service/test.yaml @@ -0,0 +1,29 @@ +# kubectl create namespace edit-test +# kubectl create service clusterip svc1 --tcp 80 --namespace=edit-test +# kubectl edit service svc1 --namespace=edit-test +description: edit a single service, add a label and change a port +mode: edit +args: +- service +- svc1 +namespace: edit-test +expectedStdout: +- service "svc1" edited +expectedExitCode: 0 +steps: +- type: request + expectedMethod: GET + expectedPath: /api/v1/namespaces/edit-test/services/svc1 + expectedInput: 0.request + resultingStatusCode: 200 + resultingOutput: 0.response +- type: edit + expectedInput: 1.original + resultingOutput: 1.edited +- type: request + expectedMethod: PATCH + expectedPath: /api/v1/namespaces/edit-test/services/svc1 + expectedContentType: application/strategic-merge-patch+json + expectedInput: 2.request + resultingStatusCode: 200 + resultingOutput: 2.response diff --git a/pkg/kubectl/cmd/testing/fake.go b/pkg/kubectl/cmd/testing/fake.go index 8a42326cffa..9440d0b6196 100644 --- a/pkg/kubectl/cmd/testing/fake.go +++ b/pkg/kubectl/cmd/testing/fake.go @@ -216,6 +216,9 @@ type TestFactory struct { Namespace string ClientConfig *restclient.Config Err error + + ClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error) + UnstructuredClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error) } type FakeFactory struct { @@ -294,7 +297,10 @@ func (f *FakeFactory) BareClientConfig() (*restclient.Config, error) { return f.tf.ClientConfig, f.tf.Err } -func (f *FakeFactory) ClientForMapping(*meta.RESTMapping) (resource.RESTClient, error) { +func (f *FakeFactory) ClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) { + if f.tf.ClientForMappingFunc != nil { + return f.tf.ClientForMappingFunc(mapping) + } return f.tf.Client, f.tf.Err } @@ -311,7 +317,10 @@ func (f *FakeFactory) ClientConfigForVersion(requiredVersion *schema.GroupVersio return nil, nil } -func (f *FakeFactory) UnstructuredClientForMapping(*meta.RESTMapping) (resource.RESTClient, error) { +func (f *FakeFactory) UnstructuredClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) { + if f.tf.UnstructuredClientForMappingFunc != nil { + return f.tf.UnstructuredClientForMappingFunc(mapping) + } return f.tf.UnstructuredClient, f.tf.Err } @@ -481,6 +490,9 @@ func (f *fakeMixedFactory) ClientForMapping(m *meta.RESTMapping) (resource.RESTC if m.ObjectConvertor == api.Scheme { return f.apiClient, f.tf.Err } + if f.tf.ClientForMappingFunc != nil { + return f.tf.ClientForMappingFunc(m) + } return f.tf.Client, f.tf.Err } @@ -553,11 +565,17 @@ func (f *fakeAPIFactory) ClientConfig() (*restclient.Config, error) { return f.tf.ClientConfig, f.tf.Err } -func (f *fakeAPIFactory) ClientForMapping(*meta.RESTMapping) (resource.RESTClient, error) { +func (f *fakeAPIFactory) ClientForMapping(m *meta.RESTMapping) (resource.RESTClient, error) { + if f.tf.ClientForMappingFunc != nil { + return f.tf.ClientForMappingFunc(m) + } return f.tf.Client, f.tf.Err } -func (f *fakeAPIFactory) UnstructuredClientForMapping(*meta.RESTMapping) (resource.RESTClient, error) { +func (f *fakeAPIFactory) UnstructuredClientForMapping(m *meta.RESTMapping) (resource.RESTClient, error) { + if f.tf.UnstructuredClientForMappingFunc != nil { + return f.tf.UnstructuredClientForMappingFunc(m) + } return f.tf.UnstructuredClient, f.tf.Err } diff --git a/staging/src/k8s.io/client-go/rest/fake/fake.go b/staging/src/k8s.io/client-go/rest/fake/fake.go index a475b8317d6..2e1bc55a985 100644 --- a/staging/src/k8s.io/client-go/rest/fake/fake.go +++ b/staging/src/k8s.io/client-go/rest/fake/fake.go @@ -48,6 +48,7 @@ type RESTClient struct { NegotiatedSerializer runtime.NegotiatedSerializer GroupName string APIRegistry *registered.APIRegistrationManager + VersionedAPIPath string Req *http.Request Resp *http.Response @@ -62,8 +63,8 @@ func (c *RESTClient) Put() *restclient.Request { return c.request("PUT") } -func (c *RESTClient) Patch(_ types.PatchType) *restclient.Request { - return c.request("PATCH") +func (c *RESTClient) Patch(pt types.PatchType) *restclient.Request { + return c.request("PATCH").SetHeader("Content-Type", string(pt)) } func (c *RESTClient) Post() *restclient.Request { @@ -110,7 +111,7 @@ func (c *RESTClient) request(verb string) *restclient.Request { serializers.StreamingSerializer = info.StreamSerializer.Serializer serializers.Framer = info.StreamSerializer.Framer } - return restclient.NewRequest(c, verb, &url.URL{Host: "localhost"}, "", config, serializers, nil, nil) + return restclient.NewRequest(c, verb, &url.URL{Host: "localhost"}, c.VersionedAPIPath, config, serializers, nil, nil) } func (c *RESTClient) Do(req *http.Request) (*http.Response, error) {