Add advanced 'kubectl edit' test scenarios

Add 'kubectl edit' testcase for saving a repeated error

Add 'kubectl edit' testcase for preserving an edited file with a syntax error

Add 'kubectl edit' testcase for recording command on list of objects
pull/6/head
Jordan Liggitt 2017-02-12 15:24:03 -05:00
parent 436fa5c9d1
commit f86db18297
No known key found for this signature in database
GPG Key ID: 24E7ADF9A3B42012
31 changed files with 708 additions and 1 deletions

View File

@ -226,6 +226,7 @@ func TestEdit(t *testing.T) {
tf.Namespace = testcase.Namespace tf.Namespace = testcase.Namespace
} }
tf.ClientConfig = defaultClientConfig() tf.ClientConfig = defaultClientConfig()
tf.Command = "edit test cmd invocation"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
errBuf := bytes.NewBuffer([]byte{}) errBuf := bytes.NewBuffer([]byte{})

View File

View File

@ -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": "1414",
"creationTimestamp": "2017-02-03T06:12:07Z",
"annotations":{"kubernetes.io/change-cause":"original creating command a"}
},
"data": {
"baz": "qux",
"foo": "changed-value",
"new-data": "new-value",
"new-data2": "new-value"
}
}

View File

View File

@ -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": "1064",
"creationTimestamp": "2017-02-03T06:11:32Z",
"annotations":{"kubernetes.io/change-cause":"original creating command b"},
"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": {}
}
}

View File

@ -0,0 +1,51 @@
# 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:
annotations:
kubernetes.io/change-cause: original creating command a
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:
annotations:
kubernetes.io/change-cause: original creating command b
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: {}

View File

@ -0,0 +1,49 @@
# 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:
annotations:
kubernetes.io/change-cause: original creating command a
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:
annotations:
kubernetes.io/change-cause: original creating command b
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: {}

View File

@ -0,0 +1,10 @@
{
"data": {
"new-data3": "newivalue"
},
"metadata": {
"annotations": {
"kubernetes.io/change-cause": "edit test cmd invocation"
}
}
}

View File

@ -0,0 +1,20 @@
{
"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",
"annotations":{"kubernetes.io/change-cause":"edit test cmd invocation"}
},
"data": {
"baz": "qux",
"foo": "changed-value",
"new-data": "new-value",
"new-data2": "new-value",
"new-data3": "newivalue"
}
}

View File

@ -0,0 +1,24 @@
{
"metadata": {
"annotations": {
"kubernetes.io/change-cause": "edit test cmd invocation"
},
"labels": {
"new-label2": "foo2"
}
},
"spec": {
"ports": [
{
"$patch": "delete",
"port": 81
},
{
"name": "80",
"port": 82,
"protocol": "TCP",
"targetPort": 81
}
]
}
}

View File

@ -0,0 +1,34 @@
{
"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",
"annotations":{"kubernetes.io/change-cause":"edit test cmd invocation"},
"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": {}
}
}

View File

@ -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

View File

@ -0,0 +1,32 @@
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "kubernetes",
"namespace": "default",
"selfLink": "/api/v1/namespaces/default/services/kubernetes",
"uid": "6a8e8829-f15f-11e6-b041-acbc32c1ca87",
"resourceVersion": "8",
"creationTimestamp": "2017-02-12T20:11:19Z",
"labels": {
"component": "apiserver",
"provider": "kubernetes"
}
},
"spec": {
"ports": [
{
"name": "https",
"protocol": "TCP",
"port": 443,
"targetPort": 443
}
],
"clusterIP": "10.0.0.1",
"type": "ClusterIP",
"sessionAffinity": "ClientIP"
},
"status": {
"loadBalancer": {}
}
}

View File

@ -0,0 +1,27 @@
# 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-12T20:11:19Z
labels:
component: apiserver
provider: kubernetes
name: kubernetes
namespace: default
resourceVersion: "8"
selfLink: /api/v1/namespaces/default/services/kubernetes
uid: 6a8e8829-f15f-11e6-b041-acbc32c1ca87
spec:
clusterIP: 10.0.0.1.1
ports:
- name: https
port: 443
protocol: TCP
targetPort: 443
sessionAffinity: ClientIP
type: ClusterIP
status:
loadBalancer: {}

View File

@ -0,0 +1,27 @@
# 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-12T20:11:19Z
labels:
component: apiserver
provider: kubernetes
name: kubernetes
namespace: default
resourceVersion: "8"
selfLink: /api/v1/namespaces/default/services/kubernetes
uid: 6a8e8829-f15f-11e6-b041-acbc32c1ca87
spec:
clusterIP: 10.0.0.1
ports:
- name: https
port: 443
protocol: TCP
targetPort: 443
sessionAffinity: ClientIP
type: ClusterIP
status:
loadBalancer: {}

View File

@ -0,0 +1,5 @@
{
"spec": {
"clusterIP": "10.0.0.1.1"
}
}

View File

@ -0,0 +1,25 @@
{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "Service \"kubernetes\" is invalid: [spec.clusterIP: Invalid value: \"10.0.0.1.1\": field is immutable, spec.clusterIP: Invalid value: \"10.0.0.1.1\": must be empty, 'None', or a valid IP address]",
"reason": "Invalid",
"details": {
"name": "kubernetes",
"kind": "Service",
"causes": [
{
"reason": "FieldValueInvalid",
"message": "Invalid value: \"10.0.0.1.1\": field is immutable",
"field": "spec.clusterIP"
},
{
"reason": "FieldValueInvalid",
"message": "Invalid value: \"10.0.0.1.1\": must be empty, 'None', or a valid IP address",
"field": "spec.clusterIP"
}
]
},
"code": 422
}

View File

@ -0,0 +1,31 @@
# 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 "kubernetes" was not valid:
# * spec.clusterIP: Invalid value: "10.0.0.1.1": field is immutable
# * spec.clusterIP: Invalid value: "10.0.0.1.1": must be empty, 'None', or a valid IP address
#
apiVersion: v1
kind: Service
metadata:
creationTimestamp: 2017-02-12T20:11:19Z
labels:
component: apiserver
provider: kubernetes
name: kubernetes
namespace: default
resourceVersion: "8"
selfLink: /api/v1/namespaces/default/services/kubernetes
uid: 6a8e8829-f15f-11e6-b041-acbc32c1ca87
spec:
clusterIP: 10.0.0.1.1
ports:
- name: https
port: 443
protocol: TCP
targetPort: 443
sessionAffinity: ClientIP
type: ClusterIP
status:
loadBalancer: {}

View File

@ -0,0 +1,31 @@
# 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 "kubernetes" was not valid:
# * spec.clusterIP: Invalid value: "10.0.0.1.1": field is immutable
# * spec.clusterIP: Invalid value: "10.0.0.1.1": must be empty, 'None', or a valid IP address
#
apiVersion: v1
kind: Service
metadata:
creationTimestamp: 2017-02-12T20:11:19Z
labels:
component: apiserver
provider: kubernetes
name: kubernetes
namespace: default
resourceVersion: "8"
selfLink: /api/v1/namespaces/default/services/kubernetes
uid: 6a8e8829-f15f-11e6-b041-acbc32c1ca87
spec:
clusterIP: 10.0.0.1.1
ports:
- name: https
port: 443
protocol: TCP
targetPort: 443
sessionAffinity: ClientIP
type: ClusterIP
status:
loadBalancer: {}

View File

@ -0,0 +1,30 @@
description: add a testcase description
mode: edit
args:
- service/kubernetes
namespace: default
expectedStderr:
- "services \"kubernetes\" is invalid"
- A copy of your changes has been stored
- Edit cancelled, no valid changes were saved
expectedExitCode: 1
steps:
- type: request
expectedMethod: GET
expectedPath: /api/v1/namespaces/default/services/kubernetes
expectedInput: 0.request
resultingStatusCode: 200
resultingOutput: 0.response
- type: edit
expectedInput: 1.original
resultingOutput: 1.edited
- type: request
expectedMethod: PATCH
expectedPath: /api/v1/namespaces/default/services/kubernetes
expectedContentType: application/strategic-merge-patch+json
expectedInput: 2.request
resultingStatusCode: 422
resultingOutput: 2.response
- type: edit
expectedInput: 3.original
resultingOutput: 3.edited

View File

@ -0,0 +1,32 @@
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "kubernetes",
"namespace": "default",
"selfLink": "/api/v1/namespaces/default/services/kubernetes",
"uid": "6a8e8829-f15f-11e6-b041-acbc32c1ca87",
"resourceVersion": "8",
"creationTimestamp": "2017-02-12T20:11:19Z",
"labels": {
"component": "apiserver",
"provider": "kubernetes"
}
},
"spec": {
"ports": [
{
"name": "https",
"protocol": "TCP",
"port": 443,
"targetPort": 443
}
],
"clusterIP": "10.0.0.1",
"type": "ClusterIP",
"sessionAffinity": "ClientIP"
},
"status": {
"loadBalancer": {}
}
}

View File

@ -0,0 +1,27 @@
# 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-12T20:11:19Z
labels:
component: apiserver
provider: kubernetes
name: kubernetes
namespace: default
resourceVersion: "8"
selfLink: /api/v1/namespaces/default/services/kubernetes
uid: 6a8e8829-f15f-11e6-b041-acbc32c1ca87
spec
clusterIP: 10.0.0.1
ports:
name: https
port: 443
protocol: TCP
targetPort: 443
sessionAffinity: ClientIP
type: ClusterIP
status:
loadBalancer: {

View File

@ -0,0 +1,27 @@
# 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-12T20:11:19Z
labels:
component: apiserver
provider: kubernetes
name: kubernetes
namespace: default
resourceVersion: "8"
selfLink: /api/v1/namespaces/default/services/kubernetes
uid: 6a8e8829-f15f-11e6-b041-acbc32c1ca87
spec:
clusterIP: 10.0.0.1
ports:
- name: https
port: 443
protocol: TCP
targetPort: 443
sessionAffinity: ClientIP
type: ClusterIP
status:
loadBalancer: {}

View File

@ -0,0 +1,30 @@
# 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.
#
# The edited file had a syntax error: unable to decode "edited-file": yaml: line 17: could not find expected ':'
#
apiVersion: v1
kind: Service
metadata:
creationTimestamp: 2017-02-12T20:11:19Z
labels:
component: apiserver
provider: kubernetes
new-label: foo
name: kubernetes
namespace: default
resourceVersion: "8"
selfLink: /api/v1/namespaces/default/services/kubernetes
uid: 6a8e8829-f15f-11e6-b041-acbc32c1ca87
spec:
clusterIP: 10.0.0.1
ports:
- name: https
port: 443
protocol: TCP
targetPort: 443
sessionAffinity: ClientIP
type: ClusterIP
status:
loadBalancer: {}

View File

@ -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.
#
# The edited file had a syntax error: unable to decode "edited-file": yaml: line 17: could not find expected ':'
#
apiVersion: v1
kind: Service
metadata:
creationTimestamp: 2017-02-12T20:11:19Z
labels:
component: apiserver
provider: kubernetes
name: kubernetes
namespace: default
resourceVersion: "8"
selfLink: /api/v1/namespaces/default/services/kubernetes
uid: 6a8e8829-f15f-11e6-b041-acbc32c1ca87
spec
clusterIP: 10.0.0.1
ports:
name: https
port: 443
protocol: TCP
targetPort: 443
sessionAffinity: ClientIP
type: ClusterIP
status:
loadBalancer: {

View File

@ -0,0 +1,7 @@
{
"metadata": {
"labels": {
"new-label": "foo"
}
}
}

View File

@ -0,0 +1,33 @@
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "kubernetes",
"namespace": "default",
"selfLink": "/api/v1/namespaces/default/services/kubernetes",
"uid": "6a8e8829-f15f-11e6-b041-acbc32c1ca87",
"resourceVersion": "1174",
"creationTimestamp": "2017-02-12T20:11:19Z",
"labels": {
"component": "apiserver",
"new-label": "foo",
"provider": "kubernetes"
}
},
"spec": {
"ports": [
{
"name": "https",
"protocol": "TCP",
"port": 443,
"targetPort": 443
}
],
"clusterIP": "10.0.0.1",
"type": "ClusterIP",
"sessionAffinity": "ClientIP"
},
"status": {
"loadBalancer": {}
}
}

View File

@ -0,0 +1,28 @@
description: edit with a syntax error, then re-edit and save
mode: edit
args:
- service/kubernetes
namespace: default
expectedStdout:
- "service \"kubernetes\" edited"
expectedExitCode: 0
steps:
- type: request
expectedMethod: GET
expectedPath: /api/v1/namespaces/default/services/kubernetes
expectedInput: 0.request
resultingStatusCode: 200
resultingOutput: 0.response
- type: edit
expectedInput: 1.original
resultingOutput: 1.edited
- type: edit
expectedInput: 2.original
resultingOutput: 2.edited
- type: request
expectedMethod: PATCH
expectedPath: /api/v1/namespaces/default/services/kubernetes
expectedContentType: application/strategic-merge-patch+json
expectedInput: 3.request
resultingStatusCode: 200
resultingOutput: 3.response

View File

@ -216,6 +216,7 @@ type TestFactory struct {
Namespace string Namespace string
ClientConfig *restclient.Config ClientConfig *restclient.Config
Err error Err error
Command string
ClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error) ClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error)
UnstructuredClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error) UnstructuredClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error)
@ -431,7 +432,7 @@ func (f *FakeFactory) PrintObjectSpecificMessage(obj runtime.Object, out io.Writ
} }
func (f *FakeFactory) Command() string { func (f *FakeFactory) Command() string {
return "" return f.tf.Command
} }
func (f *FakeFactory) BindFlags(flags *pflag.FlagSet) { func (f *FakeFactory) BindFlags(flags *pflag.FlagSet) {
@ -630,6 +631,10 @@ func (f *fakeAPIFactory) DefaultNamespace() (string, bool, error) {
return f.tf.Namespace, false, f.tf.Err return f.tf.Namespace, false, f.tf.Err
} }
func (f *fakeAPIFactory) Command() string {
return f.tf.Command
}
func (f *fakeAPIFactory) Generators(cmdName string) map[string]kubectl.Generator { func (f *fakeAPIFactory) Generators(cmdName string) map[string]kubectl.Generator {
return cmdutil.DefaultGenerators(cmdName) return cmdutil.DefaultGenerators(cmdName)
} }